linkedin-v2 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +10 -0
- data/CONTRIBUTING.md +1 -0
- data/Gemfile +8 -0
- data/LICENSE +22 -0
- data/README.md +224 -0
- data/Rakefile +19 -0
- data/lib/linked_in/access_token.rb +24 -0
- data/lib/linked_in/api.rb +108 -0
- data/lib/linked_in/api_resource.rb +180 -0
- data/lib/linked_in/communications.rb +40 -0
- data/lib/linked_in/configuration.rb +41 -0
- data/lib/linked_in/connection.rb +35 -0
- data/lib/linked_in/errors.rb +73 -0
- data/lib/linked_in/jobs.rb +11 -0
- data/lib/linked_in/mash.rb +68 -0
- data/lib/linked_in/media.rb +13 -0
- data/lib/linked_in/oauth2.rb +223 -0
- data/lib/linked_in/organizations.rb +217 -0
- data/lib/linked_in/people.rb +151 -0
- data/lib/linked_in/raise_error.rb +28 -0
- data/lib/linked_in/search.rb +70 -0
- data/lib/linked_in/share_and_social_stream.rb +143 -0
- data/lib/linked_in/version.rb +3 -0
- data/lib/linkedin-v2.rb +52 -0
- data/linkedin-v2.gemspec +39 -0
- data/pkg/linkedin-oauth2-2.0.0.gem +0 -0
- data/spec/linked_in/api/api_spec.rb +41 -0
- data/spec/linked_in/api/communications_spec.rb +13 -0
- data/spec/linked_in/api/jobs_spec.rb +33 -0
- data/spec/linked_in/api/organizations_spec.rb +54 -0
- data/spec/linked_in/api/people_spec.rb +191 -0
- data/spec/linked_in/api/search_spec.rb +71 -0
- data/spec/linked_in/api/share_and_social_stream_spec.rb +87 -0
- data/spec/linked_in/configuration_spec.rb +46 -0
- data/spec/linked_in/connection_spec.rb +10 -0
- data/spec/linked_in/module_loading_spec.rb +23 -0
- data/spec/linked_in/oauth/access_token_spec.rb +27 -0
- data/spec/linked_in/oauth/auth_code_spec.rb +86 -0
- data/spec/linked_in/oauth/credentials_spec.rb +96 -0
- data/spec/linked_in/oauth/get_access_token_spec.rb +108 -0
- data/spec/spec_helper.rb +16 -0
- data/spec/vcr_cassettes/access_token_success.yml +99 -0
- data/spec/vcr_cassettes/bad_code.yml +99 -0
- data/spec/vcr_cassettes/organization_data.yml +51 -0
- data/spec/vcr_cassettes/people_picture_urls.yml +52 -0
- data/spec/vcr_cassettes/people_profile_connections_fields.yml +52 -0
- data/spec/vcr_cassettes/people_profile_connections_other.yml +52 -0
- data/spec/vcr_cassettes/people_profile_connections_self.yml +52 -0
- data/spec/vcr_cassettes/people_profile_fields_complex.yml +52 -0
- data/spec/vcr_cassettes/people_profile_fields_simple.yml +52 -0
- data/spec/vcr_cassettes/people_profile_lang_spanish.yml +53 -0
- data/spec/vcr_cassettes/people_profile_multiple_fields.yml +52 -0
- data/spec/vcr_cassettes/people_profile_multiple_uids.yml +52 -0
- data/spec/vcr_cassettes/people_profile_multiple_uids_and_urls.yml +52 -0
- data/spec/vcr_cassettes/people_profile_multiple_urls.yml +52 -0
- data/spec/vcr_cassettes/people_profile_new_connections_fields.yml +52 -0
- data/spec/vcr_cassettes/people_profile_new_connections_other.yml +52 -0
- data/spec/vcr_cassettes/people_profile_new_connections_self.yml +52 -0
- data/spec/vcr_cassettes/people_profile_other_uid.yml +57 -0
- data/spec/vcr_cassettes/people_profile_other_url.yml +54 -0
- data/spec/vcr_cassettes/people_profile_own.yml +57 -0
- data/spec/vcr_cassettes/people_profile_own_secure.yml +53 -0
- data/spec/vcr_cassettes/people_profile_skills.yml +52 -0
- data/spec/vcr_cassettes/unavailable.yml +99 -0
- metadata +285 -0
@@ -0,0 +1,143 @@
|
|
1
|
+
module LinkedIn
|
2
|
+
# Share and Social Stream APIs
|
3
|
+
#
|
4
|
+
# @see https://developer.linkedin.com/docs/guide/v2/shares
|
5
|
+
# @see https://developer.linkedin.com/docs/guide/v2/shares/share-api
|
6
|
+
# @see https://developer.linkedin.com/docs/guide/v2/shares/network-update-social-actions
|
7
|
+
#
|
8
|
+
# LinkedIn's v2 API adherence to the documentation is shaky at best. Several of
|
9
|
+
# the calls simply don't work if you, e.g., pass the URN in as a path element
|
10
|
+
# for a resource - you have to use the ids=[URN] format w/ a single URN. Or
|
11
|
+
# sometimes passing in an "actor" parameter in the request body simply doesn't
|
12
|
+
# work, and you have to pass it in as a URL parameter. What you see in this
|
13
|
+
# file is the result of trial-and-error getting these endpoints to work, and the
|
14
|
+
# inconsistency is usually a result of either misunderstanding the docs or the
|
15
|
+
# API not working as advertised. It's also a bit unclear when the API wants
|
16
|
+
# an activity URN vs, e.g., an article URN. Caveat emptor.
|
17
|
+
#
|
18
|
+
# [(contribute here)](https://github.com/mdesjardins/linkedin-v2)
|
19
|
+
class ShareAndSocialStream < APIResource
|
20
|
+
|
21
|
+
# Retrieve shares from a person, organization, or organizationBrand.
|
22
|
+
#
|
23
|
+
# Permissions:
|
24
|
+
# 1.) For personal shares, you may only retrieve shares for the authorized members.
|
25
|
+
# 2.) For organization shares, you may only retrieve shares for organizations for which the
|
26
|
+
# authorized member is an administrator.
|
27
|
+
#
|
28
|
+
# @see https://developer.linkedin.com/docs/guide/v2/shares/share-api#retrieve
|
29
|
+
#
|
30
|
+
# @options options [String] :owner, the URN for whom we are fetching shares.
|
31
|
+
# @return [LinkedIn::Mash]
|
32
|
+
#
|
33
|
+
def shares(options = {})
|
34
|
+
urn = options.delete(:urn)
|
35
|
+
path = "/shares?q=owners&owners=#{urn}"
|
36
|
+
get(path, options)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Create one share from a person, organization, or organizationBrand.
|
40
|
+
#
|
41
|
+
# Permissions:
|
42
|
+
# 1.) For personal shares, you may only post shares as the authorized member.
|
43
|
+
# 2.) For organization shares, you may only post shares as an organization for which the
|
44
|
+
# authorized member is an administrator.
|
45
|
+
#
|
46
|
+
# @see https://developer.linkedin.com/docs/guide/v2/shares/share-api#post
|
47
|
+
#
|
48
|
+
# @option options [String] :owner, the URN of the entity posting the share.
|
49
|
+
# @return [LinkedIn::Mash]
|
50
|
+
#
|
51
|
+
def share(options = {})
|
52
|
+
path = '/shares'
|
53
|
+
defaults = {
|
54
|
+
distribution: {
|
55
|
+
linkedInDistributionTarget: {
|
56
|
+
visibleToGuest: true
|
57
|
+
}
|
58
|
+
}
|
59
|
+
}
|
60
|
+
post(path, MultiJson.dump(defaults.merge(options)), 'Content-Type' => 'application/json')
|
61
|
+
end
|
62
|
+
|
63
|
+
# Retrieves the likes for a specific post.
|
64
|
+
#
|
65
|
+
# @see https://developer.linkedin.com/docs/guide/v2/shares/network-update-social-actions#retrieve
|
66
|
+
#
|
67
|
+
# @option options [String] :urn, the URN of the relevant share, UGC post, or comment
|
68
|
+
# @return [LinkedIn::Mash]
|
69
|
+
#
|
70
|
+
def likes(options = {})
|
71
|
+
urn = options.delete(:urn)
|
72
|
+
path = "/socialActions/#{urn}/likes"
|
73
|
+
get(path, options)
|
74
|
+
end
|
75
|
+
|
76
|
+
# Likes a specific share or comment.
|
77
|
+
#
|
78
|
+
# @see https://developer.linkedin.com/docs/guide/v2/shares/network-update-social-actions#retrieve.
|
79
|
+
# @option options [String] :object, specifies the URN of the entity to which the like belongs.
|
80
|
+
# This object should be a sub-entity of the top-level share indicated in the request URL, and
|
81
|
+
# should be represented as an URN either of format urn:li:share:{id}
|
82
|
+
# @option options [String] :urn, specifies activity being un-liked (e.g., urn:li:activity::123)
|
83
|
+
# @option options [String] :actor, specifies the entity performing the action. It should be
|
84
|
+
# represented by a urn:li:person:{id} or urn:li:organization:{id} URN.
|
85
|
+
#
|
86
|
+
def like(options = {})
|
87
|
+
urn = options.delete(:urn)
|
88
|
+
path = "/socialActions/#{urn}/likes"
|
89
|
+
post(path, MultiJson.dump(options), 'Content-Type' => 'application/json')
|
90
|
+
end
|
91
|
+
|
92
|
+
# Un-likes a previously liked share or comment.
|
93
|
+
#
|
94
|
+
# @see https://developer.linkedin.com/docs/guide/v2/shares/network-update-social-actions#retrieve.
|
95
|
+
# @option options [String] :urn, specifies activity being un-liked (e.g., urn:li:activity:123)
|
96
|
+
# @option options [String] :actor, specifies the entity performing the action. It should b # represented by a urn:li:person:{id} or urn:li:organization:{id} URN.
|
97
|
+
#
|
98
|
+
def unlike(options = {})
|
99
|
+
urn = options.delete(:urn)
|
100
|
+
actor = options.delete(:actor)
|
101
|
+
path = "/socialActions/#{urn}/likes/#{actor}?actor=#{CGI::escape(actor)}"
|
102
|
+
delete(path, MultiJson.dump(options), 'Content-Type' => 'application/json') #options)
|
103
|
+
end
|
104
|
+
|
105
|
+
# Retrieves the comments for a specific post.
|
106
|
+
#
|
107
|
+
# @see https://developer.linkedin.com/docs/guide/v2/shares/network-update-social-actions#retrieve
|
108
|
+
# @option options [String] :urn, specifies activity queried for comments (e.g.,
|
109
|
+
# urn:li:article:123)
|
110
|
+
#
|
111
|
+
def comments(options = {})
|
112
|
+
urn = options.delete(:urn)
|
113
|
+
path = "/socialActions/#{urn}/comments"
|
114
|
+
get(path, options)
|
115
|
+
end
|
116
|
+
|
117
|
+
# Adds a comment to a specific post.
|
118
|
+
#
|
119
|
+
# Permissions:
|
120
|
+
#
|
121
|
+
# @see https://developer.linkedin.com/docs/guide/v2/shares/network-update-social-actions#retrieve
|
122
|
+
#
|
123
|
+
# @option options [String] :urn, specifies activity queried for comments (e.g.,
|
124
|
+
# urn:li:article:123)
|
125
|
+
# @option options [String] :actor, specifies the entity performing the action. It should b # represented by a urn:li:person:{id} or urn:li:organization:{id} URN.
|
126
|
+
# @option options [String] :message, the text content of the comment.
|
127
|
+
#
|
128
|
+
def comment(options = {})
|
129
|
+
urn = options.delete(:urn)
|
130
|
+
actor = options.delete(:actor)
|
131
|
+
message = options.delete(:message)
|
132
|
+
body = {
|
133
|
+
actor: actor,
|
134
|
+
message: {
|
135
|
+
attributes: [],
|
136
|
+
text: message
|
137
|
+
}
|
138
|
+
}
|
139
|
+
path = "/socialActions/#{urn}/comments"
|
140
|
+
post(path, MultiJson.dump(body), 'Content-Type' => 'application/json')
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
data/lib/linkedin-v2.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require "oauth2"
|
2
|
+
|
3
|
+
require "linked_in/errors"
|
4
|
+
require "linked_in/raise_error"
|
5
|
+
require "linked_in/version"
|
6
|
+
require "linked_in/configuration"
|
7
|
+
|
8
|
+
# Responsible for all authentication
|
9
|
+
# LinkedIn::OAuth2 inherits from OAuth2::Client
|
10
|
+
require "linked_in/oauth2"
|
11
|
+
|
12
|
+
# Coerces LinkedIn JSON to a nice Ruby hash
|
13
|
+
# LinkedIn::Mash inherits from Hashie::Mash
|
14
|
+
require "hashie"
|
15
|
+
require "linked_in/mash"
|
16
|
+
|
17
|
+
# Wraps a LinkedIn-specifc API connection
|
18
|
+
# LinkedIn::Connection inherits from Faraday::Connection
|
19
|
+
require "faraday"
|
20
|
+
require "linked_in/connection"
|
21
|
+
|
22
|
+
# Data object to wrap API access token
|
23
|
+
require "linked_in/access_token"
|
24
|
+
|
25
|
+
# Endpoints inherit from APIResource
|
26
|
+
require "linked_in/api_resource"
|
27
|
+
|
28
|
+
# All of the endpoints
|
29
|
+
require "linked_in/jobs"
|
30
|
+
require "linked_in/people"
|
31
|
+
require "linked_in/search"
|
32
|
+
# require "linked_in/groups" not supported by v2 API?
|
33
|
+
require "linked_in/organizations"
|
34
|
+
require "linked_in/communications"
|
35
|
+
require "linked_in/share_and_social_stream"
|
36
|
+
require 'linked_in/media'
|
37
|
+
|
38
|
+
# The primary API object that makes requests.
|
39
|
+
# It composes in all of the endpoints
|
40
|
+
require "linked_in/api"
|
41
|
+
|
42
|
+
module LinkedIn
|
43
|
+
@config = Configuration.new
|
44
|
+
|
45
|
+
class << self
|
46
|
+
attr_accessor :config
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.configure
|
50
|
+
yield self.config
|
51
|
+
end
|
52
|
+
end
|
data/linkedin-v2.gemspec
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# Follow http://guides.rubygems.org/ best practices
|
3
|
+
|
4
|
+
require File.expand_path("../lib/linked_in/version", __FILE__)
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "linkedin-v2"
|
8
|
+
gem.email = ["mike.desjardins@cereslogic.com"]
|
9
|
+
gem.version = LinkedIn::VERSION
|
10
|
+
gem.authors = ["Mike Desjardins"]
|
11
|
+
gem.summary = "Ruby wrapper for the LinkedIn v2 API"
|
12
|
+
gem.license = "MIT"
|
13
|
+
gem.homepage = "http://github.com/mdesjardins/linkedin-v2"
|
14
|
+
gem.description = gem.summary
|
15
|
+
|
16
|
+
gem.files = `git ls-files`.split("\n")
|
17
|
+
gem.test_files = `git ls-files -- spec/**/*`.split("\n")
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
# To support native JSON. Same requirements as Rails.
|
21
|
+
gem.required_ruby_version = '>= 1.9.3'
|
22
|
+
|
23
|
+
gem.add_dependency "oauth2", "~> 1.0"
|
24
|
+
gem.add_dependency "hashie", "~> 3.2"
|
25
|
+
gem.add_dependency "faraday", "~> 0.11"
|
26
|
+
|
27
|
+
gem.add_development_dependency "rake"
|
28
|
+
gem.add_development_dependency "rspec", "~> 3.0"
|
29
|
+
|
30
|
+
# We use YARD for documentation
|
31
|
+
# Extra gems for GitHub flavored MarkDown in YARD
|
32
|
+
gem.add_development_dependency "yard"
|
33
|
+
gem.add_development_dependency "redcarpet"
|
34
|
+
gem.add_development_dependency "github-markdown"
|
35
|
+
|
36
|
+
# We use VCR to mock LinkedIn API calls
|
37
|
+
gem.add_development_dependency "vcr"
|
38
|
+
gem.add_development_dependency "webmock"
|
39
|
+
end
|
Binary file
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe LinkedIn::API do
|
4
|
+
context "With no access token" do
|
5
|
+
let(:err_msg) { LinkedIn::ErrorMessages.no_access_token }
|
6
|
+
|
7
|
+
it "Raises an error" do
|
8
|
+
expect{LinkedIn::API.new}.to raise_error(LinkedIn::InvalidRequest, err_msg)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
shared_examples "test access token" do
|
13
|
+
it "Build a LinkedIn::API instance" do
|
14
|
+
expect(subject).to be_kind_of LinkedIn::API
|
15
|
+
end
|
16
|
+
|
17
|
+
it "Sets the access_token object" do
|
18
|
+
expect(subject.access_token).to be_kind_of LinkedIn::AccessToken
|
19
|
+
end
|
20
|
+
|
21
|
+
it "Sets the access_token string" do
|
22
|
+
expect(subject.access_token.token).to eq access_token
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context "With a string access token" do
|
27
|
+
let(:access_token) { "dummy_access_token" }
|
28
|
+
subject {LinkedIn::API.new(access_token)}
|
29
|
+
|
30
|
+
include_examples "test access token"
|
31
|
+
end
|
32
|
+
|
33
|
+
context "With a LinkedIn::AccessToken object" do
|
34
|
+
let(:access_token) { "dummy_access_token" }
|
35
|
+
let(:access_token_obj) { LinkedIn::AccessToken.new(access_token) }
|
36
|
+
|
37
|
+
subject {LinkedIn::API.new(access_token_obj)}
|
38
|
+
|
39
|
+
include_examples "test access token"
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe LinkedIn::Communications do
|
4
|
+
let(:access_token) {"dummy_access_token"}
|
5
|
+
let(:api) {LinkedIn::API.new(access_token)}
|
6
|
+
|
7
|
+
it "should be able to send a message" do
|
8
|
+
stub_request(:post, "https://api.linkedin.com/v1/people/~/mailbox?oauth2_access_token=dummy_access_token").to_return(body: "", status: 201)
|
9
|
+
response = api.send_message("subject", "body", ["recip1", "recip2"])
|
10
|
+
expect(response.body).to eq ""
|
11
|
+
expect(response.status).to eq 201
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe LinkedIn::Jobs, helpers: :api do
|
4
|
+
let(:access_token) {"dummy_access_token"}
|
5
|
+
let(:api) {LinkedIn::API.new(access_token)}
|
6
|
+
|
7
|
+
def stub(url)
|
8
|
+
url += "oauth2_access_token=#{access_token}"
|
9
|
+
stub_request(:get, url).to_return(body: '{}')
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should be able to view a job listing" do
|
13
|
+
stub("https://api.linkedin.com/v1/jobs/id=1586?")
|
14
|
+
expect(api.job(:id => 1586)).to be_an_instance_of(LinkedIn::Mash)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should be able to view its job bookmarks" do
|
18
|
+
stub("https://api.linkedin.com/v1/people/~/job-bookmarks?")
|
19
|
+
expect(api.job_bookmarks).to be_an_instance_of(LinkedIn::Mash)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should be able to view its job suggestion" do
|
23
|
+
stub("https://api.linkedin.com/v1/people/~/suggestions/job-suggestions?")
|
24
|
+
expect(api.job_suggestions).to be_an_instance_of(LinkedIn::Mash)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should be able to add a bookmark" do
|
28
|
+
stub_request(:post, "https://api.linkedin.com/v1/people/~/job-bookmarks?oauth2_access_token=#{access_token}").to_return(body: "", status: 201)
|
29
|
+
response = api.add_job_bookmark(id: 1452577)
|
30
|
+
expect(response.body).to eq ""
|
31
|
+
expect(response.status).to eq 201
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe LinkedIn::Organizations do
|
4
|
+
let(:access_token) {"dummy access token"}
|
5
|
+
let(:api) {LinkedIn::API.new(access_token)}
|
6
|
+
|
7
|
+
def stub(url)
|
8
|
+
stub_request(:get, url).to_return(body: '{}')
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should be able to view an organization profile" do
|
12
|
+
stub("https://api.linkedin.com/v2/organizations/1586")
|
13
|
+
expect(api.organization(id: 1586)).to be_an_instance_of(LinkedIn::Mash)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should be able to view an organization by vanity name" do
|
17
|
+
stub("https://api.linkedin.com/v2/organizations?q=vanityName&vanityName=acme")
|
18
|
+
expect(api.organization(vanity_name: "acme")).to be_an_instance_of(LinkedIn::Mash)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should be able to view an organization by e-mail domain" do
|
22
|
+
stub("https://api.linkedin.com/v2/organizations?q=emailDomain&emailDomain=acme.com")
|
23
|
+
expect(api.organization(email_domain: "acme.com")).to be_an_instance_of(LinkedIn::Mash)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should load correct organization data" do
|
27
|
+
VCR.use_cassette("organization data") do
|
28
|
+
data = api.organization(id: 11571530)
|
29
|
+
expect(data.id).to eq 11571530
|
30
|
+
expect(data.name).to eq( {"localized"=>{"en_us"=>"del Nariz Social Media"}, "preferred_locale"=>{"country"=>"US", "language"=>"en"}} )
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should load historical page statistics" do
|
35
|
+
stub("https://api.linkedin.com/v2/organizationPageStatistics?q=organization&organization=urn:li:organization:123456")
|
36
|
+
expect(
|
37
|
+
api.organization_page_statistics(urn: "urn:li:organization:123456")
|
38
|
+
).to be_an_instance_of(LinkedIn::Mash)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should load historical follow statistics" do
|
42
|
+
stub("https://api.linkedin.com/v2/organizationalEntityFollowerStatistics?q=organizationalEntity&organizationalEntity=urn:li:organization:123456")
|
43
|
+
expect(
|
44
|
+
api.organization_follower_statistics(urn: "urn:li:organization:123456")
|
45
|
+
).to be_an_instance_of(LinkedIn::Mash)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should load historical share statistics" do
|
49
|
+
stub("https://api.linkedin.com/v2/organizationalEntityShareStatistics?q=organizationalEntity&organizationalEntity=urn:li:organization:123456")
|
50
|
+
expect(
|
51
|
+
api.organization_share_statistics(urn: "urn:li:organization:123456")
|
52
|
+
).to be_an_instance_of(LinkedIn::Mash)
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,191 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe LinkedIn::People do
|
4
|
+
let(:uid) {"MpkAFJTlPY"}
|
5
|
+
let(:url) {"www.linkedin.com/in/miguel-santos-del-nariz"}
|
6
|
+
let(:access_token) {"AQVM91zzF-bLiOfCsTi8ktxnq99l-tW9meri8F9ZEWAuHf5g1bO_Pa4p0nFwKvZ7VFdSERAnJZq3eNOq6BzDPFNIyGIy50s-7HkLq2hE5uy6HrAQrsMAQR_qZxnBrSD11g_M2sF5XB5fUHZOXEQFgFaXB0M19VUAsvsz3yg-7zMI7w9Zn_DYTLO1e2W9VEZrOgVmRNt1XBIT_pdQO7pQkKv4702yJTrIBOuhZWNLZRClPHd2RRhPf2SJeTkodbnL4xSvzcyEPpLaTPyZIVJnBcsAzYFiG_pJtyGs7x-iWbUZsYgnUVSy8Wg-5eqmvze5tuZdICIP0PJ0AVMNGOxRRiLOEh8MSg"}
|
7
|
+
|
8
|
+
let(:api) {LinkedIn::API.new(access_token)}
|
9
|
+
|
10
|
+
def verify(result)
|
11
|
+
expect(result).to be_kind_of LinkedIn::Mash
|
12
|
+
end
|
13
|
+
|
14
|
+
###### PROFILES
|
15
|
+
# Self
|
16
|
+
it "grabs your own profile" do
|
17
|
+
VCR.use_cassette("people profile own") do
|
18
|
+
result = api.profile
|
19
|
+
verify result
|
20
|
+
expect(result["firstName"]).to be_kind_of String
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Secure
|
25
|
+
it "accepts secure-urls param via secure option" do
|
26
|
+
VCR.use_cassette("people profile own secure") do
|
27
|
+
verify api.profile(secure: true)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Language
|
32
|
+
it "gets profiles in a different language" do
|
33
|
+
VCR.use_cassette("people profile lang spanish") do
|
34
|
+
verify api.profile(lang: "es")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Others
|
39
|
+
it "gets another users profile by user id" do
|
40
|
+
VCR.use_cassette("people profile other uid") do
|
41
|
+
result = api.profile(id: uid)
|
42
|
+
verify result
|
43
|
+
expect(result["firstName"]).to be_kind_of String
|
44
|
+
end
|
45
|
+
end
|
46
|
+
it "gets another users profile by url" do
|
47
|
+
VCR.use_cassette("people profile other url") do
|
48
|
+
result = api.profile(url: url)
|
49
|
+
verify result
|
50
|
+
expect(result["firstName"]).to be_kind_of String
|
51
|
+
end
|
52
|
+
end
|
53
|
+
it "gets another users profile by user id" do
|
54
|
+
VCR.use_cassette("people profile other uid") do
|
55
|
+
verify api.profile(uid)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
it "gets another users profile by url" do
|
59
|
+
VCR.use_cassette("people profile other url") do
|
60
|
+
verify api.profile(url)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Errors
|
65
|
+
it "errors on bad input" do
|
66
|
+
expect{api.profile("Bad input")}.to raise_error
|
67
|
+
end
|
68
|
+
it "errors on email deprecation" do
|
69
|
+
msg = LinkedIn::ErrorMessages.deprecated
|
70
|
+
expect{api.profile(email: "email@email.com")}.to raise_error(LinkedIn::Deprecated, msg)
|
71
|
+
end
|
72
|
+
|
73
|
+
# Fields
|
74
|
+
it "grabs certain profile fields" do
|
75
|
+
VCR.use_cassette("people profile fields simple") do
|
76
|
+
result = api.profile(fields: ["id","industry"])
|
77
|
+
verify result
|
78
|
+
expect(result["industry"]).to be_kind_of String
|
79
|
+
end
|
80
|
+
end
|
81
|
+
it "grabs more complex profile fields" do
|
82
|
+
VCR.use_cassette("people profile fields complex") do
|
83
|
+
result = api.profile(fields: ["id",{"positions" => ["title"]}])
|
84
|
+
verify result
|
85
|
+
expect(result["positions"]["values"][0]["title"]).to be_kind_of String
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Multiple people
|
90
|
+
it "grabs multiple people by uids" do
|
91
|
+
VCR.use_cassette("people profile multiple uids") do
|
92
|
+
result = api.profile(ids: ["self", uid])
|
93
|
+
verify result
|
94
|
+
expect(result["values"].length).to eq 2
|
95
|
+
end
|
96
|
+
end
|
97
|
+
it "grabs multiple people by urls" do
|
98
|
+
VCR.use_cassette("people profile multiple urls") do
|
99
|
+
result = api.profile(urls: ["self", url])
|
100
|
+
verify result
|
101
|
+
expect(result["values"].length).to eq 2
|
102
|
+
end
|
103
|
+
end
|
104
|
+
it "grabs multiple people by uids and urls" do
|
105
|
+
VCR.use_cassette("people profile multiple uids and urls") do
|
106
|
+
result = api.profile(ids: ["self", uid], urls: [url])
|
107
|
+
verify result
|
108
|
+
expect(result["values"].length).to eq 3
|
109
|
+
end
|
110
|
+
end
|
111
|
+
it "grabs certain fields for multiple people" do
|
112
|
+
VCR.use_cassette("people profile multiple fields") do
|
113
|
+
result = api.profile(ids: ["self", uid], fields: ["id", "industry"])
|
114
|
+
verify result
|
115
|
+
expect(result["values"][0]["industry"]).to be_kind_of String
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
###### CONNECTIONS
|
120
|
+
it "grabs your own connections" do
|
121
|
+
VCR.use_cassette("people profile connections self") do
|
122
|
+
result = api.connections
|
123
|
+
verify result
|
124
|
+
expect(result["values"].length).to eq 3
|
125
|
+
end
|
126
|
+
end
|
127
|
+
it "grabs the connections of others" do
|
128
|
+
VCR.use_cassette("people profile connections other") do
|
129
|
+
result = api.connections(id: uid)
|
130
|
+
verify result
|
131
|
+
expect(result["values"].length).to eq 3
|
132
|
+
end
|
133
|
+
end
|
134
|
+
it "grabs certain fields for those connections" do
|
135
|
+
VCR.use_cassette("people profile connections fields") do
|
136
|
+
result = api.connections(fields: ["id", "industry"])
|
137
|
+
verify result
|
138
|
+
expect(result["values"].length).to eq 4
|
139
|
+
expect(result["values"][0]["industry"]).to be_kind_of String
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
it "grabs new connections since a string date" do
|
144
|
+
VCR.use_cassette("people profile new connections self") do
|
145
|
+
result = api.new_connections("2014-01-01")
|
146
|
+
verify result
|
147
|
+
expect(result["values"].length).to eq 2
|
148
|
+
end
|
149
|
+
end
|
150
|
+
it "grabs new connections since a numeric date" do
|
151
|
+
VCR.use_cassette("people profile new connections self") do
|
152
|
+
verify api.new_connections(1388534400000)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
it "grabs new connections since a Time.utc object" do
|
156
|
+
VCR.use_cassette("people profile new connections self") do
|
157
|
+
verify api.new_connections(Time.utc(2014,1,1))
|
158
|
+
end
|
159
|
+
end
|
160
|
+
it "grabs new connections for another user" do
|
161
|
+
VCR.use_cassette("people profile new connections other") do
|
162
|
+
result = api.new_connections("2014-01-01", id: uid)
|
163
|
+
verify result
|
164
|
+
expect(result["values"].length).to eq 2
|
165
|
+
end
|
166
|
+
end
|
167
|
+
it "grabs certain fields of new connections" do
|
168
|
+
VCR.use_cassette("people profile new connections fields") do
|
169
|
+
result = api.new_connections("2014-01-01", fields: ["id", "industry"])
|
170
|
+
verify result
|
171
|
+
expect(result["values"].length).to eq 3
|
172
|
+
expect(result["values"][0]["industry"]).to be_kind_of String
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
it "grabs picture urls" do
|
177
|
+
VCR.use_cassette("people picture urls") do
|
178
|
+
result = api.picture_urls
|
179
|
+
verify result
|
180
|
+
expect(result["values"][0] =~ URI::regexp).to_not be_nil
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
it "grabs skills" do
|
185
|
+
VCR.use_cassette("people profile skills") do
|
186
|
+
result = api.skills
|
187
|
+
verify result
|
188
|
+
expect(result["all"].length).to eq 2
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|