linkedin-v2 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +10 -0
  3. data/CONTRIBUTING.md +1 -0
  4. data/Gemfile +8 -0
  5. data/LICENSE +22 -0
  6. data/README.md +224 -0
  7. data/Rakefile +19 -0
  8. data/lib/linked_in/access_token.rb +24 -0
  9. data/lib/linked_in/api.rb +108 -0
  10. data/lib/linked_in/api_resource.rb +180 -0
  11. data/lib/linked_in/communications.rb +40 -0
  12. data/lib/linked_in/configuration.rb +41 -0
  13. data/lib/linked_in/connection.rb +35 -0
  14. data/lib/linked_in/errors.rb +73 -0
  15. data/lib/linked_in/jobs.rb +11 -0
  16. data/lib/linked_in/mash.rb +68 -0
  17. data/lib/linked_in/media.rb +13 -0
  18. data/lib/linked_in/oauth2.rb +223 -0
  19. data/lib/linked_in/organizations.rb +217 -0
  20. data/lib/linked_in/people.rb +151 -0
  21. data/lib/linked_in/raise_error.rb +28 -0
  22. data/lib/linked_in/search.rb +70 -0
  23. data/lib/linked_in/share_and_social_stream.rb +143 -0
  24. data/lib/linked_in/version.rb +3 -0
  25. data/lib/linkedin-v2.rb +52 -0
  26. data/linkedin-v2.gemspec +39 -0
  27. data/pkg/linkedin-oauth2-2.0.0.gem +0 -0
  28. data/spec/linked_in/api/api_spec.rb +41 -0
  29. data/spec/linked_in/api/communications_spec.rb +13 -0
  30. data/spec/linked_in/api/jobs_spec.rb +33 -0
  31. data/spec/linked_in/api/organizations_spec.rb +54 -0
  32. data/spec/linked_in/api/people_spec.rb +191 -0
  33. data/spec/linked_in/api/search_spec.rb +71 -0
  34. data/spec/linked_in/api/share_and_social_stream_spec.rb +87 -0
  35. data/spec/linked_in/configuration_spec.rb +46 -0
  36. data/spec/linked_in/connection_spec.rb +10 -0
  37. data/spec/linked_in/module_loading_spec.rb +23 -0
  38. data/spec/linked_in/oauth/access_token_spec.rb +27 -0
  39. data/spec/linked_in/oauth/auth_code_spec.rb +86 -0
  40. data/spec/linked_in/oauth/credentials_spec.rb +96 -0
  41. data/spec/linked_in/oauth/get_access_token_spec.rb +108 -0
  42. data/spec/spec_helper.rb +16 -0
  43. data/spec/vcr_cassettes/access_token_success.yml +99 -0
  44. data/spec/vcr_cassettes/bad_code.yml +99 -0
  45. data/spec/vcr_cassettes/organization_data.yml +51 -0
  46. data/spec/vcr_cassettes/people_picture_urls.yml +52 -0
  47. data/spec/vcr_cassettes/people_profile_connections_fields.yml +52 -0
  48. data/spec/vcr_cassettes/people_profile_connections_other.yml +52 -0
  49. data/spec/vcr_cassettes/people_profile_connections_self.yml +52 -0
  50. data/spec/vcr_cassettes/people_profile_fields_complex.yml +52 -0
  51. data/spec/vcr_cassettes/people_profile_fields_simple.yml +52 -0
  52. data/spec/vcr_cassettes/people_profile_lang_spanish.yml +53 -0
  53. data/spec/vcr_cassettes/people_profile_multiple_fields.yml +52 -0
  54. data/spec/vcr_cassettes/people_profile_multiple_uids.yml +52 -0
  55. data/spec/vcr_cassettes/people_profile_multiple_uids_and_urls.yml +52 -0
  56. data/spec/vcr_cassettes/people_profile_multiple_urls.yml +52 -0
  57. data/spec/vcr_cassettes/people_profile_new_connections_fields.yml +52 -0
  58. data/spec/vcr_cassettes/people_profile_new_connections_other.yml +52 -0
  59. data/spec/vcr_cassettes/people_profile_new_connections_self.yml +52 -0
  60. data/spec/vcr_cassettes/people_profile_other_uid.yml +57 -0
  61. data/spec/vcr_cassettes/people_profile_other_url.yml +54 -0
  62. data/spec/vcr_cassettes/people_profile_own.yml +57 -0
  63. data/spec/vcr_cassettes/people_profile_own_secure.yml +53 -0
  64. data/spec/vcr_cassettes/people_profile_skills.yml +52 -0
  65. data/spec/vcr_cassettes/unavailable.yml +99 -0
  66. metadata +285 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 188d3b8c708aa23a58b655c5e2196919bb9bba99
4
+ data.tar.gz: b8391342b546d18f5b8c322a002a81d262863745
5
+ SHA512:
6
+ metadata.gz: ca09e965f66642dfc2dec5d63554be7980a828e6f0c4cfc6d2e20f8bc923209971013319131e0e2f10469e163c03fb958b3fa100d368252d15b431b232e2cc40
7
+ data.tar.gz: e2cc077b53c6e9bf080d73822e18fcad500e6a5a6a1d9f8abf71da3ade3d1d1082268fed3aabea01cf5bdb38f03b1629c75e15923e86ea61715415a009556140
@@ -0,0 +1,10 @@
1
+ # Changelog
2
+
3
+ ## 1.0.0 - August 1, 2014
4
+
5
+ * Complete re-architecture of the Oauth2.0 gem.
6
+
7
+ ## 0.1.0 - July 15, 2013
8
+
9
+ * Migrated API over to use Linkedin's OAuth 2.0
10
+ * **NOTE:** This was based off of a heavily modified fork from hexgnu/linkedin
@@ -0,0 +1 @@
1
+ Read [GitHub's "Contributing to Open Source on GitHub"](https://guides.github.com/activities/contributing-to-open-source/)
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Dependencies defined in linkedin-oauth2.gemspec
4
+ gemspec
5
+
6
+ group :test do
7
+ gem "coveralls", require: false
8
+ end
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2014-present Evan Morikawa (evan@evanmorikawa.com) 2013-2014
4
+ Matt Kirk 2009-11 Wynn Netherland.
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in
14
+ all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
+ THE SOFTWARE.
@@ -0,0 +1,224 @@
1
+ # LinkedIn v2
2
+
3
+ ## WARNING: DANGER WILL ROBINSON
4
+
5
+ This is very much a work in progress. Currently only the shares/social stream
6
+ and organization related endpoints have been verified to work. Having said that,
7
+ those endpoints are using this gem in a production application, so they're
8
+ reliable enough. :)
9
+
10
+ Many endpoints still need to be written, and as I don't have the requisite partner
11
+ status w/ LinkedIn, I can't develop against the jobs API. Many of the specs still
12
+ fail. *Caveat emptor*
13
+
14
+ ## NOW BACK TO YOUR REGULARLY SCHEDULED PROGRAMMING
15
+
16
+ Ruby wrapper for v2 if the [LinkedIn API](http://developer.linkedin.com). This gem is entirely
17
+ based on emorikawa's excellent [linkedin-oauth2](https://github.com/emorikawa/linkedin-oauth2)
18
+ gem.
19
+
20
+ If you are using OAuth 1.0, see [hexgnu/linkedin](https://github.com/hexgnu/linkedin)
21
+ If you are using OAuth 2.0 and the v1 LinkedIn API, see [emorikawa/linkedin-oauth2](https://github.com/emorikawa/linkedin-oauth2), on which this gem is based.
22
+
23
+ # Installation
24
+
25
+ In Bundler:
26
+
27
+ ```ruby
28
+ gem "linkedin-v2", "~> 0.1.0"
29
+ ```
30
+
31
+ Otherwise:
32
+
33
+ [sudo|rvm] gem install linkedin-v2
34
+
35
+ # Usage
36
+
37
+ **[Step 1:](#step-1-register-your-application)** [Register](https://www.linkedin.com/secure/developer) your
38
+ application with LinkedIn. They will give you a **Client ID** (aka API
39
+ Key) and a **Client Secret** (aka Secret Key)
40
+
41
+ **[Step 2:](#step-2-getting-an-access-token)** Use your **Client ID** and **Client Secret** to obtain an **Access Token** from some user.
42
+
43
+ **[Step 3:](#step-3-using-linkedins-api)** Use an **Access Token** to query the API.
44
+
45
+ ```ruby
46
+ api = LinkedIn::API.new(access_token)
47
+ me = api.profile
48
+ ```
49
+
50
+ ## Step 1: Register your Application
51
+
52
+ You first need to create and register an application with LinkedIn
53
+ [here](https://www.linkedin.com/secure/developer).
54
+
55
+ You will not be able to use any part of the API without registering first.
56
+
57
+ Once you have registered you will need to take note of a few key items on
58
+ your Application Details page.
59
+
60
+ 1. **API Key** - We refer to this as your client id or `client_id`
61
+ 1. **Secret Key** - We refer to this as your client secret or
62
+ `client_secret`
63
+ 1. **Default Scope** - This is the set of permissions you request from
64
+ users when they connect to your app. If you want to set this on a
65
+ request-by-request basis, you can use the `scope` option with the
66
+ `auth_code_url` method.
67
+ 1. **OAuth 2.0 Redirect URLs** - For security reasons, the url you enter
68
+ in this box must exactly match the `redirect_uri` you use in this gem.
69
+
70
+ You do NOT need **OAuth User Token** nor **OAuth User Secret**. That is
71
+ for OAuth 1.0. This gem is for OAuth 2.0.
72
+
73
+ ## Step 2: Getting An Access Token
74
+
75
+ All LinkedIn API requests must be made in the context of an access token.
76
+ The access token encodes what LinkedIn information your AwesomeApp® can
77
+ gather on behalf of "John Doe".
78
+
79
+ There are a few different ways to get an access token from a user.
80
+
81
+ 1. You can use [LinkedIn's Javascript API](https://developer.linkedin.com/documents/javascript-api-reference-0) to authenticate on the front-end and then pass the access token to the backend via [this procedure](https://developer.linkedin.com/documents/exchange-jsapi-tokens-rest-api-oauth-tokens).
82
+
83
+ 1. If you use OmniAuth, I would recommend looking at [decioferreira/omniauth-linkedin-oauth2](https://github.com/decioferreira/omniauth-linkedin-oauth2) to help automate authentication.
84
+
85
+ 1. You can do it manually using this linkedin-oauth2 gem and the steps
86
+ below.
87
+
88
+ Here is how to get an access token using this linkedin-oauth2 gem:
89
+
90
+ ### Step 2A: Configuration
91
+
92
+ You will need to configure the following items:
93
+
94
+ 1. Your **client id** (aka API Key)
95
+ 1. Your **client secret** (aka Secret Key)
96
+ 1. Your **redirect uri**. On LinkedIn's website you must input a list of
97
+ valid redirect URIs. If you use the same one each time, you can set it
98
+ in the `LinkedIn.configure` block. If your redirect uris change
99
+ depending on business logic, you can pass it into the `auth_code_url`
100
+ method.
101
+
102
+ ```ruby
103
+ # It's best practice to keep secret credentials out of source code.
104
+ # You can, of course, hardcode dev keys or directly pass them in as the
105
+ # first two arguments of LinkedIn::OAuth2.new
106
+ LinkedIn.configure do |config|
107
+ config.client_id = ENV["LINKEDIN_CLIENT_ID"]
108
+ config.client_secret = ENV["LINKEDIN_CLIENT_SECRET"]
109
+
110
+ # This must exactly match the redirect URI you set on your application's
111
+ # settings page. If your redirect_uri is dynamic, pass it into
112
+ # `auth_code_url` instead.
113
+ config.redirect_uri = "https://getawesomeapp.io/linkedin/oauth2"
114
+ end
115
+ ```
116
+
117
+ ### Step 2B: Get Auth Code URL
118
+
119
+ ```ruby
120
+ oauth = LinkedIn::OAuth2.new
121
+
122
+ url = oauth.auth_code_url
123
+ ```
124
+
125
+ ### Step 2C: User Sign In
126
+
127
+ You must now load url from Step 2B in a browser. It will pull up the
128
+ LinkedIn sign in box. Once LinkedIn user credentials are entered, the box
129
+ will close and redirect to your redirect url, passing along with it the
130
+ **OAuth code** as the `code` GET param.
131
+
132
+ Be sure to read the extended documentation around the LinkedIn::OAuth2
133
+ module for more options you can set.
134
+
135
+ **Note:** The **OAuth code** only lasts for ~20 seconds!
136
+
137
+ ### Step 2D: Get Access Token
138
+
139
+ ```ruby
140
+ code = "THE_OAUTH_CODE_LINKEDIN_GAVE_ME"
141
+
142
+ access_token = oauth.get_access_token(code)
143
+ ```
144
+
145
+ Now that you have an access token, you can use it to query the API.
146
+
147
+ The `LinkedIn::OAuth2` inherits from [intreda/oauth2](https://github.com/intridea/oauth2)'s `OAuth2::Client` class. See that gem's [documentation](https://github.com/intridea/oauth2/blob/master/lib/oauth2/client.rb) for more usage examples.
148
+
149
+ ## Step 3: Using LinkedIn's API
150
+
151
+ Once you have an access token, you can query LinkedIn's API.
152
+
153
+ Your access token encodes the permissions you're allowed to have. See Step
154
+ 2 and [this LinkedIn document](https://developer.linkedin.com/documents/authentication#granting) for how to change the permissions. See each section's documentation on LinkedIn for more information on what permissions get you access to.
155
+
156
+ ### People
157
+
158
+ ## TBD
159
+
160
+ ### Organizations
161
+
162
+ Detailed overviews of Organizations
163
+
164
+ See https://developer.linkedin.com/docs/guide/v2/organizations
165
+
166
+ ```ruby
167
+ # Organization info
168
+ api.organization(name: "google")
169
+ api.organization(id: 12345)
170
+ api.organization(urn: 'urn:li:organization:12345')
171
+ ```
172
+
173
+ ### Jobs
174
+
175
+ ## DON'T HAVE ACCESS. :(
176
+ ```
177
+
178
+ ### Share and Social Stream
179
+
180
+ View and update content on social streams
181
+
182
+ See https://developer.linkedin.com/docs/guide/v2/shares
183
+
184
+ ```ruby
185
+ # Your news feed
186
+ api.shares
187
+
188
+ api.share(content: "hi")
189
+
190
+ # For a particular feed item
191
+ api.comments(urn: "urn:li:article:12345")
192
+ api.likes(urn: "urn:li:article:12345")
193
+
194
+ api.like(urn: "urn:li:activity:12345")
195
+ api.unlike(urn: "urn:li:activity:12345")
196
+ ```
197
+
198
+ ### Communications
199
+
200
+ ## TBD
201
+
202
+ # Documentation
203
+
204
+ On [RubyDoc here](http://rubydoc.info/github/mdesjardins/linkedin-v2/frames/file/README.md)
205
+
206
+ Read the source for [LinkedIn::API](https://github.com/mdesjardins/linkedin-v2/blob/master/lib/linked_in/api.rb) and [LinkedIn::OAuth2](https://github.com/mdesjardins/linkedin-v2/blob/master/lib/linked_in/oauth2.rb)
207
+
208
+ # Contributing
209
+
210
+ Please see [CONTRIBUTING.md](https://github.com/mdesjardins/linkedin-v2/blob/master/CONTRIBUTING.md) for details.
211
+
212
+ # Credits
213
+ Huge, huge props to Evan Morikawa for writing the v1 version of this gem. This gem is
214
+ pretty much all of that work, but gutted and replaced with v2 endpoints.
215
+
216
+ * [Evan Morikawa](https://twitter.com/eom) ([emorikawa](https://github.com/emorikawa))
217
+ * [Matt Kirk](http://matthewkirk.com) ([hexgnu](https://github.com/hexgnu))
218
+ * [Wynn Netherland](http://wynnetherland.com) ([pengwynn](https://github.com/pengwynn))
219
+ * Josh Kalderimis ([joshk](https://github.com/joshk))
220
+ * Erik Michaels-Ober ([sferik](https://github.com/sferik))
221
+ * And Many More [Contributors](https://github.com/emorikawa/linkedin-oauth2/graphs/contributors)
222
+
223
+ # License
224
+ Copyright :copyright: 2018-present [Mike Desjardins](https://twitter.com/mdesjardins) 2014-2018 [Evan Morikawa](https://twitter.com/e0m) 2013-2014 [Matt Kirk](http://matthewkirk.com/) 2009-11 [Wynn Netherland](http://wynnnetherland.com/) and [contributors](https://github.com/emorikawa/linkedin-oauth2/graphs/contributors). It is free software, and may be redistributed under the terms specified in the MIT-LICENSE file. See [LICENSE](https://github.com/emorikawa/linkedin-oauth2/blob/master/LICENSE) for details.
@@ -0,0 +1,19 @@
1
+ # Adds the following task:
2
+ # spec - Run RSpec tests & setup $LOAD_PATH properly
3
+ #
4
+ # We recommend you set the following RSpec options in your own ~/.rspec
5
+ # --color
6
+ # --format documentation
7
+ # --profile
8
+ # --order rand
9
+ require 'rspec/core/rake_task'
10
+ RSpec::Core::RakeTask.new(:spec)
11
+
12
+ # Adds the following tasks:
13
+ # build - Build gem in pkg/ directory
14
+ # install - Build and install gem
15
+ # release - Create tag, build gem, and push it to Rubygems
16
+ require 'bundler/gem_helper'
17
+ Bundler::GemHelper.install_tasks
18
+
19
+ task default: :spec
@@ -0,0 +1,24 @@
1
+ module LinkedIn
2
+ # A simple data object to contain the token string and expiration data.
3
+ class AccessToken
4
+ attr_accessor :token, :expires_in, :expires_at
5
+
6
+ # Creates a simple data wrapper for an access token.
7
+ #
8
+ # LinkedIn returns only an `expires_in` value. This calculates and
9
+ # sets and `expires_at` field for convenience.
10
+ #
11
+ # @param [String] token the access token
12
+ # @param [FixNum] expires_in number of seconds the token lasts for
13
+ # @param [Time] expires_at when the token will expire.
14
+ def initialize(token=nil, expires_in=nil, expires_at=nil)
15
+ self.token = token
16
+ self.expires_in = expires_in
17
+ if expires_at.nil? and not self.expires_in.nil?
18
+ self.expires_at = Time.now + expires_in
19
+ else
20
+ self.expires_at = expires_at
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,108 @@
1
+ module LinkedIn
2
+ class API
3
+
4
+ attr_accessor :access_token
5
+
6
+ def initialize(access_token=nil)
7
+ access_token = parse_access_token(access_token)
8
+ verify_access_token!(access_token)
9
+ @access_token = access_token
10
+
11
+ @connection = LinkedIn::Connection.new params: default_params,
12
+ headers: default_headers
13
+
14
+ initialize_endpoints
15
+ end
16
+
17
+ extend Forwardable # Composition over inheritance
18
+
19
+ # I do not have access to the jobs related endpoints.
20
+ # def_delegators :@jobs, :job,
21
+ # :job_bookmarks,
22
+ # :job_suggestions,
23
+ # :add_job_bookmark
24
+
25
+ def_delegators :@people, :profile,
26
+ :skills,
27
+ :connections,
28
+ :picture_urls,
29
+ :new_connections
30
+
31
+ def_delegators :@search, :search
32
+
33
+ # Not part of v2??
34
+ # def_delegators :@groups, :join_group,
35
+ # :group_posts,
36
+ # :group_profile,
37
+ # :add_group_share,
38
+ # :group_suggestions,
39
+ # :group_memberships,
40
+ # :post_group_discussion
41
+
42
+ def_delegators :@organizations, :organization,
43
+ :brand,
44
+ :organization_acls,
45
+ :organization_search,
46
+ :organization_page_statistics,
47
+ :organization_follower_statistics,
48
+ :organization_share_statistics
49
+
50
+ def_delegators :@communications, :send_message
51
+
52
+ def_delegators :@share_and_social_stream, :shares,
53
+ :share,
54
+ :likes,
55
+ :like,
56
+ :unlike,
57
+ :comments,
58
+ :comment
59
+ # :update_comment,
60
+ # :network_updates
61
+
62
+ def_delegators :@media, :summary
63
+
64
+ private ##############################################################
65
+
66
+ def initialize_endpoints
67
+ @jobs = LinkedIn::Jobs.new(@connection)
68
+ @people = LinkedIn::People.new(@connection)
69
+ @search = LinkedIn::Search.new(@connection)
70
+ # @groups = LinkedIn::Groups.new(@connection) not supported by v2 API?
71
+ @organizations = LinkedIn::Organizations.new(@connection)
72
+ @communications = LinkedIn::Communications.new(@connection)
73
+ @share_and_social_stream = LinkedIn::ShareAndSocialStream.new(@connection)
74
+ @media = LinkedIn::Media.new(@connection)
75
+ end
76
+
77
+ def default_params
78
+ # LIv2 TODO - Probably can just remove?
79
+ # https//developer.linkedin.com/documents/authentication
80
+ #return { oauth2_access_token: @access_token.token }
81
+ {}
82
+ end
83
+
84
+ def default_headers
85
+ # https://developer.linkedin.com/documents/api-requests-json
86
+ return {"x-li-format" => "json", "Authorization" => "Bearer #{@access_token.token}"}
87
+ end
88
+
89
+ def verify_access_token!(access_token)
90
+ if not access_token.is_a? LinkedIn::AccessToken
91
+ raise no_access_token_error
92
+ end
93
+ end
94
+
95
+ def parse_access_token(access_token)
96
+ if access_token.is_a? LinkedIn::AccessToken
97
+ return access_token
98
+ elsif access_token.is_a? String
99
+ return LinkedIn::AccessToken.new(access_token)
100
+ end
101
+ end
102
+
103
+ def no_access_token_error
104
+ msg = LinkedIn::ErrorMessages.no_access_token
105
+ LinkedIn::InvalidRequest.new(msg)
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,180 @@
1
+ module LinkedIn
2
+ # The abstract class all API endpoints inherit from. Providers common
3
+ # builder methods across all endpoints.
4
+ #
5
+ # @!macro profile_options
6
+ # @options opts [String] :id LinkedIn ID to fetch profile for
7
+ # @options opts [String] :url The profile url
8
+ # @options opts [String] :lang Requests the language of the profile.
9
+ # Options are: en, fr, de, it, pt, es
10
+ # @options opts [Array, Hash] :fields fields to fetch. The list of
11
+ # fields can be found at
12
+ # https://developer.linkedin.com/documents/profile-fields
13
+ # @options opts [String] :secure (true) specify if urls in the
14
+ # response should be https
15
+ # @options opts [String] :"secure-urls" (true) alias to secure option
16
+ #
17
+ # @!macro share_input_fields
18
+ # @param [Hash] share content of the share
19
+ # @option share [String] :comment
20
+ # @option share [String] :content
21
+ # @option share [String] :title
22
+ # @option share [String] :submitted-url
23
+ # @option share [String] :submitted-image-url
24
+ # @option share [String] :description
25
+ # @option share [String] :visibility
26
+ # @option share [String] :code
27
+ #
28
+ # @!macro organization_path_options
29
+ # @param [Hash] options identifies the organization profile you want
30
+ # @option options [String] :email_domain organization email domain
31
+ # @option options [String] :id organization ID
32
+ # @option options [String] :urn organization URN
33
+ # @option options [String] :vanity_name organization vanity name
34
+ #
35
+ # @!macro brand_path_options
36
+ # @param [Hash] options identifies the brand profile you want
37
+ # @option options [String] :id brand ID
38
+ # @option options [String] :vanity_name brand vanity name
39
+ # @option options [String] :parent_id brand's parent organization ID.
40
+ class APIResource
41
+
42
+ def initialize(connection)
43
+ @connection = connection
44
+ end
45
+
46
+ def urn_to_id(urn)
47
+ urn.split(':').last
48
+ end
49
+
50
+ def id_to_urn(resource, id)
51
+ ['urn', 'li', resource, id].join(':')
52
+ end
53
+
54
+ protected ############################################################
55
+
56
+ def get(path, options={})
57
+ url, params, headers = prepare_connection_params(path, options)
58
+
59
+ response = @connection.get(url, params, headers)
60
+ Mash.from_json(response.body)
61
+ end
62
+
63
+ def post(path=nil, body=nil, headers=nil, &block)
64
+ @connection.post(prepend_prefix(path), body, headers, &block)
65
+ end
66
+
67
+ def put(path=nil, body=nil, headers=nil, &block)
68
+ @connection.put(prepend_prefix(path), body, headers, &block)
69
+ Mash.from_json(response.body)
70
+ end
71
+
72
+ def delete(path=nil, body=nil, headers=nil, &block)
73
+ # @connection.delete(prepend_prefix(path), params, headers, &block)
74
+ # To be able to DELETE with a body:
75
+ reponse = @connection.run_request(:delete, prepend_prefix(path), body, headers, &block)
76
+
77
+ Mash.from_json(response.body)
78
+ end
79
+
80
+ def deprecated
81
+ LinkedIn::Deprecated.new(LinkedIn::ErrorMessages.deprecated)
82
+ end
83
+
84
+ private ##############################################################
85
+
86
+ def prepend_prefix(path)
87
+ return @connection.path_prefix + path
88
+ end
89
+
90
+ def prepare_connection_params(path, options)
91
+ path = prepend_prefix(path)
92
+ path += generate_field_selectors(options)
93
+
94
+ headers = options.delete(:headers) || {}
95
+
96
+ params = format_options_for_query(options)
97
+
98
+ return [path, params, headers]
99
+ end
100
+
101
+ # Dasherizes the param keys
102
+ def format_options_for_query(options)
103
+ options.reduce({}) do |list, kv|
104
+ key, value = kv.first.to_s.gsub("_","-"), kv.last
105
+ list[key] = value
106
+ list
107
+ end
108
+ end
109
+
110
+ def generate_field_selectors(options)
111
+ default = LinkedIn.config.default_profile_fields || {}
112
+ fields = options.delete(:fields) || default
113
+ if options.delete(:public)
114
+ return ":public"
115
+ elsif fields.empty?
116
+ return ""
117
+ else
118
+ return "?projection=(#{fields})"
119
+ end
120
+ end
121
+
122
+ def build_fields_params(fields)
123
+ if fields.is_a?(Hash) && !fields.empty?
124
+ fields.map {|v| "(#{build_fields_params(v)})" }.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 profile_path(options={}, allow_multiple=true)
133
+ path = "/people"
134
+
135
+ id = options.delete(:id)
136
+ url = options.delete(:url)
137
+
138
+ ids = options.delete(:ids)
139
+ urls = options.delete(:urls)
140
+
141
+ if options.delete(:email) then raise deprecated end
142
+
143
+ if (id or url)
144
+ path += single_person_path(id, url)
145
+ elsif allow_multiple and (ids or urls)
146
+ path += multiple_people_path(ids, urls)
147
+ else
148
+ path = "/me"
149
+ end
150
+ end
151
+
152
+ def single_person_path(id=nil, url=nil)
153
+ if id
154
+ return "/id=#{id}"
155
+ elsif url
156
+ return "/url=#{CGI.escape(url)}"
157
+ else
158
+ return "/me"
159
+ end
160
+ end
161
+
162
+ # See syntax here: https://developer.linkedin.com/documents/field-selectors
163
+ def multiple_people_path(ids=[], urls=[])
164
+ if ids.nil? then ids = [] end
165
+ if urls.nil? then urls = [] end
166
+
167
+ ids = ids.map do |id|
168
+ if is_self(id) then "me" else "id=#{id}" end
169
+ end
170
+ urls = urls.map do |url|
171
+ if is_self(url) then "me" else "url=#{CGI.escape(url)}" end
172
+ end
173
+ return "::(#{(ids+urls).join(",")})"
174
+ end
175
+
176
+ def is_self(str)
177
+ str == "self" or str == "me"
178
+ end
179
+ end
180
+ end