linkedin-build 1.1.14

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +7 -0
  2. data/.autotest +14 -0
  3. data/.gemtest +0 -0
  4. data/.gitignore +49 -0
  5. data/.rspec +1 -0
  6. data/.travis.yml +6 -0
  7. data/.yardopts +7 -0
  8. data/CHANGELOG.md +99 -0
  9. data/EXAMPLES.md +202 -0
  10. data/Gemfile +11 -0
  11. data/LICENSE +22 -0
  12. data/README.md +43 -0
  13. data/Rakefile +15 -0
  14. data/lib/linked_in/api.rb +38 -0
  15. data/lib/linked_in/api/communications.rb +44 -0
  16. data/lib/linked_in/api/companies.rb +129 -0
  17. data/lib/linked_in/api/groups.rb +115 -0
  18. data/lib/linked_in/api/jobs.rb +64 -0
  19. data/lib/linked_in/api/people.rb +73 -0
  20. data/lib/linked_in/api/query_helpers.rb +86 -0
  21. data/lib/linked_in/api/share_and_social_stream.rb +137 -0
  22. data/lib/linked_in/client.rb +51 -0
  23. data/lib/linked_in/errors.rb +29 -0
  24. data/lib/linked_in/helpers.rb +6 -0
  25. data/lib/linked_in/helpers/authorization.rb +69 -0
  26. data/lib/linked_in/helpers/request.rb +85 -0
  27. data/lib/linked_in/mash.rb +95 -0
  28. data/lib/linked_in/search.rb +71 -0
  29. data/lib/linked_in/version.rb +11 -0
  30. data/lib/linkedin.rb +35 -0
  31. data/linkedin-build.gemspec +28 -0
  32. data/spec/cases/api_spec.rb +308 -0
  33. data/spec/cases/linkedin_spec.rb +37 -0
  34. data/spec/cases/mash_spec.rb +113 -0
  35. data/spec/cases/oauth_spec.rb +178 -0
  36. data/spec/cases/search_spec.rb +234 -0
  37. data/spec/fixtures/cassette_library/LinkedIn_Api/Company_API.yml +81 -0
  38. data/spec/fixtures/cassette_library/LinkedIn_Api/Company_API/should_load_correct_company_data.yml +81 -0
  39. data/spec/fixtures/cassette_library/LinkedIn_Client/_authorize_from_request/should_return_a_valid_access_token.yml +37 -0
  40. data/spec/fixtures/cassette_library/LinkedIn_Client/_request_token/with_a_callback_url/should_return_a_valid_access_token.yml +37 -0
  41. data/spec/fixtures/cassette_library/LinkedIn_Client/_request_token/with_default_options/should_return_a_valid_request_token.yml +37 -0
  42. data/spec/fixtures/cassette_library/LinkedIn_Search/_search/by_company_name_option/should_perform_a_search.yml +92 -0
  43. data/spec/fixtures/cassette_library/LinkedIn_Search/_search/by_email_address/should_perform_a_people_search.yml +57 -0
  44. data/spec/fixtures/cassette_library/LinkedIn_Search/_search/by_first_name_and_last_name_options/should_perform_a_search.yml +100 -0
  45. data/spec/fixtures/cassette_library/LinkedIn_Search/_search/by_first_name_and_last_name_options_with_fields/should_perform_a_search.yml +114 -0
  46. data/spec/fixtures/cassette_library/LinkedIn_Search/_search/by_keywords_string_parameter/should_perform_a_search.yml +52 -0
  47. data/spec/fixtures/cassette_library/LinkedIn_Search/_search/by_multiple_email_address/should_perform_a_multi-email_search.yml +59 -0
  48. data/spec/fixtures/cassette_library/LinkedIn_Search/_search/by_single_keywords_option/should_perform_a_search.yml +52 -0
  49. data/spec/fixtures/cassette_library/LinkedIn_Search/_search/by_single_keywords_option_with_pagination/should_perform_a_search.yml +43 -0
  50. data/spec/fixtures/cassette_library/LinkedIn_Search/_search/email_search_returns_unauthorized/should_raise_an_unauthorized_error.yml +59 -0
  51. data/spec/fixtures/cassette_library/LinkedIn_Search/_search_company/by_keywords_options_with_fields/should_perform_a_search.yml +43 -0
  52. data/spec/fixtures/cassette_library/LinkedIn_Search/_search_company/by_keywords_string_parameter/should_perform_a_company_search.yml +80 -0
  53. data/spec/fixtures/cassette_library/LinkedIn_Search/_search_company/by_single_keywords_option/should_perform_a_company_search.yml +80 -0
  54. data/spec/fixtures/cassette_library/LinkedIn_Search/_search_company/by_single_keywords_option_with_facets_to_return/should_return_a_facet.yml +80 -0
  55. data/spec/fixtures/cassette_library/LinkedIn_Search/_search_company/by_single_keywords_option_with_pagination/should_perform_a_search.yml +74 -0
  56. data/spec/helper.rb +34 -0
  57. metadata +282 -0
@@ -0,0 +1,95 @@
1
+ require 'hashie'
2
+ require 'multi_json'
3
+
4
+ module LinkedIn
5
+
6
+ # The generalized pseudo-object that is returned for all query
7
+ # requests.
8
+ class Mash < ::Hashie::Mash
9
+
10
+ # Convert a json string to a Mash
11
+ #
12
+ # @param [String] json_string
13
+ # @return [LinkedIn::Mash]
14
+ def self.from_json(json_string)
15
+ result_hash = ::MultiJson.decode(json_string)
16
+ new(result_hash)
17
+ end
18
+
19
+ # Returns a Date if we have year, month and day, and no conflicting key
20
+ #
21
+ # @return [Date]
22
+ def to_date
23
+ if !self.has_key?('to_date') && contains_date_fields?
24
+ Date.civil(self.year, self.month, self.day)
25
+ else
26
+ super
27
+ end
28
+ end
29
+
30
+ # Returns the id of the object from LinkedIn
31
+ #
32
+ # @return [String]
33
+ def id
34
+ if self['id']
35
+ self['id']
36
+ else
37
+ self['_key']
38
+ end
39
+ end
40
+
41
+ # Convert the 'timestamp' field from a string to a Time object
42
+ #
43
+ # @return [Time]
44
+ def timestamp
45
+ value = self['timestamp']
46
+ if value.kind_of? Integer
47
+ value = value / 1000 if value > 9999999999
48
+ Time.at(value)
49
+ else
50
+ value
51
+ end
52
+ end
53
+
54
+ # Return the results array from the query
55
+ #
56
+ # @return [Array]
57
+ def all
58
+ super || []
59
+ end
60
+
61
+ protected
62
+
63
+ def contains_date_fields?
64
+ self.year? && self.month? && self.day?
65
+ end
66
+
67
+ # overload the convert_key mash method so that the LinkedIn
68
+ # keys are made a little more ruby-ish
69
+ def convert_key(key)
70
+ case key.to_s
71
+ when '_total'
72
+ 'total'
73
+ when 'values'
74
+ 'all'
75
+ when 'numResults'
76
+ 'total_results'
77
+ else
78
+ underscore(key)
79
+ end
80
+ end
81
+
82
+ # borrowed from ActiveSupport
83
+ # no need require an entire lib when we only need one method
84
+ def underscore(camel_cased_word)
85
+ word = camel_cased_word.to_s.dup
86
+ word.gsub!(/::/, '/')
87
+ word.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
88
+ word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
89
+ word.tr!("-", "_")
90
+ word.downcase!
91
+ word
92
+ end
93
+
94
+ end
95
+ end
@@ -0,0 +1,71 @@
1
+ module LinkedIn
2
+
3
+ module Search
4
+
5
+ # Retrieve search results of the given object type
6
+ #
7
+ # Permissions: (for people search only) r_network
8
+ #
9
+ # @note People Search API is a part of the Vetted API Access Program. You
10
+ # must apply and get approval before using this API
11
+ #
12
+ # @see http://developer.linkedin.com/documents/people-search-api People Search
13
+ # @see http://developer.linkedin.com/documents/job-search-api Job Search
14
+ # @see http://developer.linkedin.com/documents/company-search Company Search
15
+ #
16
+ # @param [Hash] options search input fields
17
+ # @param [String] type type of object to return ('people', 'job' or 'company')
18
+ # @return [LinkedIn::Mash]
19
+ def search(options={}, type='people')
20
+
21
+ path = "/#{type.to_s}-search"
22
+
23
+ if options.is_a?(Hash)
24
+ fields = options.delete(:fields)
25
+ path += field_selector(fields) if fields
26
+ end
27
+
28
+ options = { :keywords => options } if options.is_a?(String)
29
+ options = format_options_for_query(options)
30
+
31
+ result_json = get(to_uri(path, options))
32
+
33
+ Mash.from_json(result_json)
34
+ end
35
+
36
+ private
37
+
38
+ def format_options_for_query(opts)
39
+ opts.inject({}) do |list, kv|
40
+ key, value = kv.first.to_s.gsub("_","-"), kv.last
41
+ list[key] = sanitize_value(value)
42
+ list
43
+ end
44
+ end
45
+
46
+ def sanitize_value(value)
47
+ value = value.join("+") if value.is_a?(Array)
48
+ value = value.gsub(" ", "+") if value.is_a?(String)
49
+ value
50
+ end
51
+
52
+ def field_selector(fields)
53
+ result = ":("
54
+ fields = fields.to_a.map do |field|
55
+ if field.is_a?(Hash)
56
+ innerFields = []
57
+ field.each do |key, value|
58
+ innerFields << key.to_s.gsub("_","-") + field_selector(value)
59
+ end
60
+ innerFields.join(',')
61
+ else
62
+ field.to_s.gsub("_","-")
63
+ end
64
+ end
65
+ result += fields.join(',')
66
+ result += ")"
67
+ result
68
+ end
69
+ end
70
+
71
+ end
@@ -0,0 +1,11 @@
1
+ module LinkedIn
2
+
3
+ module VERSION #:nodoc:
4
+ MAJOR = 1
5
+ MINOR = 1
6
+ PATCH = 14
7
+ PRE = nil
8
+ STRING = [MAJOR, MINOR, PATCH, PRE].compact.join('.')
9
+ end
10
+
11
+ end
@@ -0,0 +1,35 @@
1
+ require 'oauth'
2
+
3
+ module LinkedIn
4
+
5
+ class << self
6
+ attr_accessor :token, :secret, :default_profile_fields
7
+
8
+ # config/initializers/linkedin.rb (for instance)
9
+ #
10
+ # ```ruby
11
+ # LinkedIn.configure do |config|
12
+ # config.token = 'consumer_token'
13
+ # config.secret = 'consumer_secret'
14
+ # config.default_profile_fields = ['educations', 'positions']
15
+ # end
16
+ # ```
17
+ # elsewhere
18
+ #
19
+ # ```ruby
20
+ # client = LinkedIn::Client.new
21
+ # ```
22
+ def configure
23
+ yield self
24
+ true
25
+ end
26
+ end
27
+
28
+ autoload :Api, "linked_in/api"
29
+ autoload :Client, "linked_in/client"
30
+ autoload :Mash, "linked_in/mash"
31
+ autoload :Errors, "linked_in/errors"
32
+ autoload :Helpers, "linked_in/helpers"
33
+ autoload :Search, "linked_in/search"
34
+ autoload :Version, "linked_in/version"
35
+ end
@@ -0,0 +1,28 @@
1
+ # encoding: utf-8
2
+ require File.expand_path('../lib/linked_in/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.add_dependency 'hashie', '3.5.6' #'~> 3.0'
6
+ gem.add_dependency 'multi_json', '~> 1.0'
7
+ gem.add_dependency 'oauth', '0.5.1' # '~> 0.4'
8
+ gem.add_dependency 'oauth2', '1.4.0'
9
+ # gem.add_development_dependency 'json', '~> 1.6'
10
+ gem.add_development_dependency 'rake', '~> 10'
11
+ gem.add_development_dependency 'yard'
12
+ gem.add_development_dependency 'kramdown'
13
+ gem.add_development_dependency 'rspec', '~> 2.13'
14
+ gem.add_development_dependency 'simplecov', '~> 0.7'
15
+ gem.add_development_dependency 'vcr', '~> 2.5'
16
+ gem.add_development_dependency 'webmock', '~> 1.11'
17
+ gem.authors = ['Matthew Kirk', 'Wynn Netherland', 'Josh Kalderimis']
18
+ gem.description = 'Ruby wrapper for the LinkedIn API'
19
+ gem.email = ['meteor.kirk@gmail.com', 'wynn.netherland@gmail.com', 'josh.kalderimis@gmail.com']
20
+ gem.files = `git ls-files`.split("\n")
21
+ gem.homepage = 'http://github.com/hexgnu/linkedin'
22
+ gem.name = 'linkedin-build'
23
+ gem.licenses = %w[MIT]
24
+ gem.require_paths = ['lib']
25
+ gem.summary = 'This gem interfaces with the Linkedin XML and JSON APis'
26
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
27
+ gem.version = LinkedIn::VERSION::STRING
28
+ end
@@ -0,0 +1,308 @@
1
+ require 'helper'
2
+
3
+ describe LinkedIn::Api do
4
+ before do
5
+ LinkedIn.default_profile_fields = nil
6
+ client.stub(:consumer).and_return(consumer)
7
+ client.authorize_from_access('atoken', 'asecret')
8
+ end
9
+
10
+ let(:client){LinkedIn::Client.new('token', 'secret')}
11
+ let(:consumer){OAuth::Consumer.new('token', 'secret', {:site => 'https://api.linkedin.com'})}
12
+
13
+ it "should be able to view the account profile" do
14
+ stub_request(:get, "https://api.linkedin.com/v1/people/~").to_return(:body => "{}")
15
+ client.profile.should be_an_instance_of(LinkedIn::Mash)
16
+ end
17
+
18
+ it "should be able to view public profiles" do
19
+ stub_request(:get, "https://api.linkedin.com/v1/people/id=123").to_return(:body => "{}")
20
+ client.profile(:id => 123).should be_an_instance_of(LinkedIn::Mash)
21
+ end
22
+
23
+ it "should be able to view the picture urls" do
24
+ stub_request(:get, "https://api.linkedin.com/v1/people/~/picture-urls::(original)").to_return(:body => "{}")
25
+ client.picture_urls.should be_an_instance_of(LinkedIn::Mash)
26
+ end
27
+
28
+ it "should be able to view connections" do
29
+ stub_request(:get, "https://api.linkedin.com/v1/people/~/connections").to_return(:body => "{}")
30
+ client.connections.should be_an_instance_of(LinkedIn::Mash)
31
+ end
32
+
33
+ it "should be able to view new connections" do
34
+ modified_since = Time.now.to_i * 1000
35
+ stub_request(:get, "https://api.linkedin.com/v1/people/~/connections?modified=new&modified-since=#{modified_since}").to_return(:body => "{}")
36
+ client.new_connections(modified_since).should be_an_instance_of(LinkedIn::Mash)
37
+ end
38
+
39
+ it "should be able to view network_updates" do
40
+ stub_request(:get, "https://api.linkedin.com/v1/people/~/network/updates").to_return(:body => "{}")
41
+ client.network_updates.should be_an_instance_of(LinkedIn::Mash)
42
+ end
43
+
44
+ it "should be able to view network_update's comments" do
45
+ stub_request(:get, "https://api.linkedin.com/v1/people/~/network/updates/key=network_update_key/update-comments").to_return(:body => "{}")
46
+ client.share_comments("network_update_key").should be_an_instance_of(LinkedIn::Mash)
47
+ end
48
+
49
+ it "should be able to view network_update's likes" do
50
+ stub_request(:get, "https://api.linkedin.com/v1/people/~/network/updates/key=network_update_key/likes").to_return(:body => "{}")
51
+ client.share_likes("network_update_key").should be_an_instance_of(LinkedIn::Mash)
52
+ end
53
+
54
+ it "should be able to search with a keyword if given a String" do
55
+ stub_request(:get, "https://api.linkedin.com/v1/people-search?keywords=business").to_return(:body => "{}")
56
+ client.search("business").should be_an_instance_of(LinkedIn::Mash)
57
+ end
58
+
59
+ it "should be able to search with an option" do
60
+ stub_request(:get, "https://api.linkedin.com/v1/people-search?first-name=Javan").to_return(:body => "{}")
61
+ client.search(:first_name => "Javan").should be_an_instance_of(LinkedIn::Mash)
62
+ end
63
+
64
+ it "should be able to search with an option and fetch specific fields" do
65
+ stub_request(:get, "https://api.linkedin.com/v1/people-search:(num-results,total)?first-name=Javan").to_return(
66
+ :body => "{}")
67
+ client.search(:first_name => "Javan", :fields => ["num_results", "total"]).should be_an_instance_of(LinkedIn::Mash)
68
+ end
69
+
70
+ it "should be able to share a new status" do
71
+ stub_request(:post, "https://api.linkedin.com/v1/people/~/shares").to_return(:body => "", :status => 201)
72
+ response = client.add_share(:comment => "Testing, 1, 2, 3")
73
+ response.body.should == nil
74
+ response.status.should == "201"
75
+ end
76
+
77
+ it "should be able to share a new company status" do
78
+ stub_request(:post, "https://api.linkedin.com/v1/companies/123456/shares").to_return(:body => "", :status => 201)
79
+ response = client.add_company_share("123456", { :comment => "Testing, 1, 2, 3" })
80
+ response.body.should == nil
81
+ response.status.should == "201"
82
+ end
83
+
84
+ it "returns the shares for a person" do
85
+ stub_request(:get, "https://api.linkedin.com/v1/people/~/network/updates?type=SHAR&scope=self&after=1234&count=35").to_return(
86
+ :body => "{}")
87
+ client.shares(:after => 1234, :count => 35)
88
+ end
89
+
90
+ it "should be able to fetch a single share" do
91
+ stub_request(:get, "https://api.linkedin.com/v1/people/~/network/updates/key=network_update_key").to_return(:body => "{}")
92
+ client.share("network_update_key").should be_an_instance_of(LinkedIn::Mash)
93
+ end
94
+
95
+ it "should be able to comment on network update" do
96
+ stub_request(:post, "https://api.linkedin.com/v1/people/~/network/updates/key=SOMEKEY/update-comments").to_return(
97
+ :body => "", :status => 201)
98
+ response = client.update_comment('SOMEKEY', "Testing, 1, 2, 3")
99
+ response.body.should == nil
100
+ response.status.should == "201"
101
+ end
102
+
103
+ it "should be able to like a network update" do
104
+ stub_request(:put, "https://api.linkedin.com/v1/people/~/network/updates/key=SOMEKEY/is-liked").
105
+ with(:body => "true").to_return(:body => "", :status => 201)
106
+ response = client.like_share('SOMEKEY')
107
+ response.body.should == nil
108
+ response.status.should == "201"
109
+ end
110
+
111
+ it "should be able to unlike a network update" do
112
+ stub_request(:put, "https://api.linkedin.com/v1/people/~/network/updates/key=SOMEKEY/is-liked").
113
+ with(:body => "false").to_return(:body => "", :status => 201)
114
+ response = client.unlike_share('SOMEKEY')
115
+ response.body.should == nil
116
+ response.status.should == "201"
117
+ end
118
+
119
+ it "should be able to pass down the additional arguments to OAuth's get_request_token" do
120
+ consumer.should_receive(:get_request_token).with(
121
+ {:oauth_callback => "http://localhost:3000/auth/callback"}, :scope => "rw_nus").and_return("request_token")
122
+
123
+ request_token = client.request_token(
124
+ {:oauth_callback => "http://localhost:3000/auth/callback"}, :scope => "rw_nus"
125
+ )
126
+
127
+ request_token.should == "request_token"
128
+ end
129
+
130
+ context "Company API", :vcr do
131
+
132
+ it "should be able to view a company profile" do
133
+ stub_request(:get, "https://api.linkedin.com/v1/companies/id=1586").to_return(:body => "{}")
134
+ client.company(:id => 1586).should be_an_instance_of(LinkedIn::Mash)
135
+ end
136
+
137
+ it "should be able to view a company by universal name" do
138
+ stub_request(:get, "https://api.linkedin.com/v1/companies/universal-name=acme").to_return(:body => "{}")
139
+ client.company(:name => 'acme').should be_an_instance_of(LinkedIn::Mash)
140
+ end
141
+
142
+ it "should be able to view a company by e-mail domain" do
143
+ stub_request(:get, "https://api.linkedin.com/v1/companies?email-domain=acme.com").to_return(:body => "{}")
144
+ client.company(:domain => 'acme.com').should be_an_instance_of(LinkedIn::Mash)
145
+ end
146
+
147
+ it "should be able to view a user's company pages" do
148
+ stub_request(:get, "https://api.linkedin.com/v1/companies?is-company-admin=true").to_return(:body => "{}")
149
+ client.company(:is_admin => 'true').should be_an_instance_of(LinkedIn::Mash)
150
+ end
151
+
152
+ it "should be able to page a user's company pages" do
153
+ stub_request(:get, "https://api.linkedin.com/v1/companies?is-company-admin=true&count=10&start=0").to_return(:body => "{}")
154
+ client.company(:is_admin => 'true', :count => 10, :start => 0).should be_an_instance_of(LinkedIn::Mash)
155
+ end
156
+
157
+ it "should load correct company data" do
158
+ client.company(:id => 1586).name.should == "Amazon"
159
+
160
+ data = client.company(:id => 1586, :fields => %w{ id name industry locations:(address:(city state country-code) is-headquarters) employee-count-range })
161
+ data.id.should == 1586
162
+ data.name.should == "Amazon"
163
+ data.employee_count_range.name.should == "10001+"
164
+ data.industry.should == "Internet"
165
+ data.locations.all[0].address.city.should == "Seattle"
166
+ data.locations.all[0].is_headquarters.should == true
167
+ end
168
+
169
+ it "should be able to view company_updates" do
170
+ stub_request(:get, "https://api.linkedin.com/v1/companies/id=1586/updates").to_return(:body => "{}")
171
+ client.company_updates(:id => 1586).should be_an_instance_of(LinkedIn::Mash)
172
+ end
173
+
174
+ it "should be able to view company_statistic" do
175
+ stub_request(:get, "https://api.linkedin.com/v1/companies/id=1586/company-statistics").to_return(:body => "{}")
176
+ client.company_statistics(:id => 1586).should be_an_instance_of(LinkedIn::Mash)
177
+ end
178
+
179
+ it "should be able to view company updates comments" do
180
+ stub_request(:get, "https://api.linkedin.com/v1/companies/id=1586/updates/key=company_update_key/update-comments").to_return(:body => "{}")
181
+ client.company_updates_comments("company_update_key", :id => 1586).should be_an_instance_of(LinkedIn::Mash)
182
+ end
183
+
184
+ it "should be able to view company updates likes" do
185
+ stub_request(:get, "https://api.linkedin.com/v1/companies/id=1586/updates/key=company_update_key/likes").to_return(:body => "{}")
186
+ client.company_updates_likes("company_update_key", :id => 1586).should be_an_instance_of(LinkedIn::Mash)
187
+ end
188
+
189
+ it "should be able to follow a company" do
190
+ stub_request(:post, "https://api.linkedin.com/v1/people/~/following/companies").to_return(:body => "", :status => 201)
191
+
192
+ response = client.follow_company(1586)
193
+ response.body.should == nil
194
+ response.status.should == "201"
195
+ end
196
+
197
+ it "should be able to unfollow a company" do
198
+ stub_request(:delete, "https://api.linkedin.com/v1/people/~/following/companies/id=1586").to_return(:body => "", :status => 201)
199
+
200
+ response = client.unfollow_company(1586)
201
+ response.body.should == nil
202
+ response.status.should == "201"
203
+ end
204
+
205
+ end
206
+
207
+ context "Job API", :vcr do
208
+
209
+ it "should be able to view a job listing" do
210
+ stub_request(:get, "https://api.linkedin.com/v1/jobs/id=1586").to_return(:body => "{}")
211
+ client.job(:id => 1586).should be_an_instance_of(LinkedIn::Mash)
212
+ end
213
+
214
+ it "should be able to view its job bookmarks" do
215
+ stub_request(:get, "https://api.linkedin.com/v1/people/~/job-bookmarks").to_return(:body => "{}")
216
+ client.job_bookmarks.should be_an_instance_of(LinkedIn::Mash)
217
+ end
218
+
219
+ it "should be able to view its job suggestion" do
220
+ stub_request(:get, "https://api.linkedin.com/v1/people/~/suggestions/job-suggestions").to_return(:body => "{}")
221
+ client.job_suggestions.should be_an_instance_of(LinkedIn::Mash)
222
+ end
223
+
224
+ it "should be able to add a bookmark" do
225
+ stub_request(:post, "https://api.linkedin.com/v1/people/~/job-bookmarks").to_return(:body => "", :status => 201)
226
+ response = client.add_job_bookmark(:id => 1452577)
227
+ response.body.should == nil
228
+ response.status.should == "201"
229
+ end
230
+ end
231
+
232
+ context "Group API" do
233
+
234
+ it "should be able to list group memberships for a profile" do
235
+ stub_request(:get, "https://api.linkedin.com/v1/people/~/group-memberships").to_return(:body => "{}")
236
+ client.group_memberships.should be_an_instance_of(LinkedIn::Mash)
237
+ end
238
+
239
+ it "should be able to list suggested groups for a profile" do
240
+ stub_request(:get, "https://api.linkedin.com/v1/people/~/suggestions/groups").to_return(:body => '{"id": "123"}')
241
+ response = client.group_suggestions
242
+ response.id.should == '123'
243
+ end
244
+
245
+ it "should be able to parse nested fields" do
246
+ stub_request(:get, "https://api.linkedin.com/v1/people/~/group-memberships:(group:(id,name,small-logo-url,short-description))").to_return(:body => "{}")
247
+ client.group_memberships(:fields => [{:group => ['id', 'name', 'small-logo-url', 'short-description']}]).should be_an_instance_of(LinkedIn::Mash)
248
+ end
249
+
250
+ it "should be able to join a group" do
251
+ stub_request(:put, "https://api.linkedin.com/v1/people/~/group-memberships/123").to_return(:body => "", :status => 201)
252
+
253
+ response = client.join_group(123)
254
+ response.body.should == nil
255
+ response.status.should == "201"
256
+ end
257
+
258
+ it "should be able to list a group profile" do
259
+ stub_request(:get, "https://api.linkedin.com/v1/groups/123").to_return(:body => '{"id": "123"}')
260
+ response = client.group_profile(:id => 123)
261
+ response.id.should == '123'
262
+ end
263
+
264
+ it "should be able to list group posts" do
265
+ stub_request(:get, "https://api.linkedin.com/v1/groups/123/posts").to_return(:body => '{"id": "123"}')
266
+ response = client.group_posts(:id => 123)
267
+ response.id.should == '123'
268
+ end
269
+
270
+ it 'should be able to post a discussion to a group' do
271
+ expected = {
272
+ 'title' => 'New Discussion',
273
+ 'summary' => 'New Summary',
274
+ 'content' => {
275
+ "submitted-url" => "http://www.google.com"
276
+ }
277
+ }
278
+
279
+ stub_request(:post, "https://api.linkedin.com/v1/groups/123/posts").with(:body => expected).to_return(:body => "", :status => 201)
280
+ response = client.post_group_discussion(123, expected)
281
+ response.body.should == nil
282
+ response.status.should == '201'
283
+ end
284
+
285
+ it "should be able to share a new group status" do
286
+ stub_request(:post, "https://api.linkedin.com/v1/groups/1/posts").to_return(:body => "", :status => 201)
287
+ response = client.add_group_share(1, :comment => "Testing, 1, 2, 3")
288
+ response.body.should == nil
289
+ response.status.should == "201"
290
+ end
291
+ end
292
+
293
+ context "Communication API" do
294
+ it "should be able to send a message" do
295
+ stub_request(:post, "https://api.linkedin.com/v1/people/~/mailbox").to_return(:body => "", :status => 201)
296
+ response = client.send_message("subject", "body", ["recip1", "recip2"])
297
+ response.body.should == nil
298
+ response.status.should == "201"
299
+ end
300
+ end
301
+
302
+ context "Errors" do
303
+ it "should raise AccessDeniedError when LinkedIn returns 403 status code" do
304
+ stub_request(:get, "https://api.linkedin.com/v1/people-search?first-name=Javan").to_return(:body => "{}", :status => 403)
305
+ expect{ client.search(:first_name => "Javan") }.to raise_error(LinkedIn::Errors::AccessDeniedError)
306
+ end
307
+ end
308
+ end