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,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
@@ -0,0 +1,3 @@
1
+ module LinkedIn
2
+ VERSION = '0.1.3'
3
+ end
@@ -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
@@ -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
@@ -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