linkedin-v2 0.1.3

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 (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