linkedin-oauth2 0.1.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +9 -9
  2. data/.gitignore +24 -39
  3. data/.travis.yml +4 -4
  4. data/.yardopts +2 -0
  5. data/CHANGELOG.md +10 -0
  6. data/CONTRIBUTING.md +1 -0
  7. data/Gemfile +6 -5
  8. data/LICENSE +19 -17
  9. data/README.md +399 -0
  10. data/Rakefile +15 -22
  11. data/lib/linked_in/access_token.rb +24 -0
  12. data/lib/linked_in/api.rb +96 -3
  13. data/lib/linked_in/api_resource.rb +165 -0
  14. data/lib/linked_in/communications.rb +40 -0
  15. data/lib/linked_in/companies.rb +146 -0
  16. data/lib/linked_in/configuration.rb +41 -0
  17. data/lib/linked_in/connection.rb +31 -0
  18. data/lib/linked_in/errors.rb +33 -13
  19. data/lib/linked_in/groups.rb +116 -0
  20. data/lib/linked_in/jobs.rb +68 -0
  21. data/lib/linked_in/mash.rb +34 -34
  22. data/lib/linked_in/oauth2.rb +223 -0
  23. data/lib/linked_in/people.rb +141 -0
  24. data/lib/linked_in/search.rb +58 -43
  25. data/lib/linked_in/share_and_social_stream.rb +128 -0
  26. data/lib/linked_in/version.rb +1 -9
  27. data/lib/linkedin-oauth2.rb +43 -25
  28. data/linkedin-oauth2.gemspec +35 -21
  29. data/spec/linked_in/api/api_spec.rb +41 -0
  30. data/spec/linked_in/api/communications_spec.rb +13 -0
  31. data/spec/linked_in/api/companies_spec.rb +59 -0
  32. data/spec/linked_in/api/groups_spec.rb +55 -0
  33. data/spec/linked_in/api/jobs_spec.rb +33 -0
  34. data/spec/linked_in/api/people_spec.rb +181 -0
  35. data/spec/linked_in/api/search_spec.rb +71 -0
  36. data/spec/linked_in/api/share_and_social_stream_spec.rb +60 -0
  37. data/spec/linked_in/configuration_spec.rb +46 -0
  38. data/spec/linked_in/connection_spec.rb +10 -0
  39. data/spec/linked_in/module_loading_spec.rb +23 -0
  40. data/spec/linked_in/oauth/access_token_spec.rb +27 -0
  41. data/spec/linked_in/oauth/auth_code_spec.rb +86 -0
  42. data/spec/linked_in/oauth/credentials_spec.rb +96 -0
  43. data/spec/linked_in/oauth/get_access_token_spec.rb +108 -0
  44. data/spec/spec_helper.rb +15 -0
  45. data/spec/vcr_cassettes/access_token_success.yml +84 -0
  46. data/spec/vcr_cassettes/bad_code.yml +78 -0
  47. data/spec/vcr_cassettes/companies_data.yml +44 -0
  48. data/spec/vcr_cassettes/invalid_access_token.yml +60 -0
  49. data/spec/vcr_cassettes/not_found.yml +64 -0
  50. data/spec/vcr_cassettes/people_picture_urls.yml +54 -0
  51. data/spec/vcr_cassettes/people_profile_connections_fields.yml +73 -0
  52. data/spec/vcr_cassettes/people_profile_connections_other.yml +78 -0
  53. data/spec/vcr_cassettes/people_profile_connections_self.yml +78 -0
  54. data/spec/vcr_cassettes/people_profile_fields_complex.yml +70 -0
  55. data/spec/vcr_cassettes/people_profile_fields_simple.yml +57 -0
  56. data/spec/vcr_cassettes/people_profile_lang_spanish.yml +59 -0
  57. data/spec/vcr_cassettes/people_profile_multiple_fields.yml +68 -0
  58. data/spec/vcr_cassettes/people_profile_multiple_uids.yml +70 -0
  59. data/spec/vcr_cassettes/people_profile_multiple_uids_and_urls.yml +76 -0
  60. data/spec/vcr_cassettes/people_profile_multiple_urls.yml +70 -0
  61. data/spec/vcr_cassettes/people_profile_new_connections_fields.yml +69 -0
  62. data/spec/vcr_cassettes/people_profile_new_connections_other.yml +72 -0
  63. data/spec/vcr_cassettes/people_profile_new_connections_self.yml +72 -0
  64. data/spec/vcr_cassettes/people_profile_other_uid.yml +59 -0
  65. data/spec/vcr_cassettes/people_profile_other_url.yml +59 -0
  66. data/spec/vcr_cassettes/people_profile_own.yml +59 -0
  67. data/spec/vcr_cassettes/people_profile_own_secure.yml +59 -0
  68. data/spec/vcr_cassettes/unauthorized.yml +61 -0
  69. data/spec/vcr_cassettes/unavailable.yml +81 -0
  70. metadata +145 -88
  71. data/.autotest +0 -14
  72. data/.document +0 -5
  73. data/.gemtest +0 -0
  74. data/.rspec +0 -1
  75. data/.ruby-gemset +0 -1
  76. data/.ruby-version +0 -1
  77. data/README.markdown +0 -121
  78. data/changelog.markdown +0 -94
  79. data/examples/authenticate.rb +0 -16
  80. data/examples/network.rb +0 -12
  81. data/examples/profile.rb +0 -18
  82. data/examples/sinatra.rb +0 -69
  83. data/examples/status.rb +0 -6
  84. data/lib/linked_in/api/query_methods.rb +0 -123
  85. data/lib/linked_in/api/update_methods.rb +0 -76
  86. data/lib/linked_in/client.rb +0 -31
  87. data/lib/linked_in/helpers.rb +0 -6
  88. data/lib/linked_in/helpers/authorization.rb +0 -106
  89. data/lib/linked_in/helpers/request.rb +0 -93
  90. data/spec/cases/api_spec.rb +0 -192
  91. data/spec/cases/linkedin_spec.rb +0 -37
  92. data/spec/cases/mash_spec.rb +0 -85
  93. data/spec/cases/oauth_spec.rb +0 -130
  94. data/spec/cases/search_spec.rb +0 -190
  95. data/spec/helper.rb +0 -30
@@ -0,0 +1,141 @@
1
+ require 'time'
2
+ module LinkedIn
3
+ # People APIs
4
+ #
5
+ # @see http://developer.linkedin.com/documents/people People API
6
+ # @see http://developer.linkedin.com/documents/profile-fields Profile Fields
7
+ # @see http://developer.linkedin.com/documents/field-selectors Field Selectors
8
+ # @see http://developer.linkedin.com/documents/accessing-out-network-profiles Accessing Out of Network Profiles
9
+ class People < APIResource
10
+
11
+ # @!macro multi_profile_options
12
+ # @options opts [Array] :urls A list of profile urls
13
+ # @options opts [Array] :ids List of LinkedIn IDs
14
+ #
15
+ # @!macro new profile_args
16
+ # @overload profile()
17
+ # Fetches your own profile
18
+ # @overload profile(id_or_url, opts)
19
+ # Fetches the profile of another user
20
+ # @param [String] id_or_url a LinkedIn id or a profile URL
21
+ # @param [Hash] opts more profile options
22
+ # @macro profile_options
23
+ # @overload profile(opts)
24
+ # Fetches the profile of another user
25
+ # @param [Hash] opts profile options
26
+ # @macro profile_options
27
+ # @return [LinkedIn::Mash]
28
+
29
+ # Retrieve a member's LinkedIn profile.
30
+ #
31
+ # Required permissions: r_basicprofile, r_fullprofile
32
+ #
33
+ # @see http://developer.linkedin.com/documents/profile-api
34
+ # @macro profile_args
35
+ # @macro multi_profile_options
36
+ def profile(id={}, options={})
37
+ options = parse_id(id, options)
38
+ path = profile_path(options)
39
+ get(path, options)
40
+ end
41
+
42
+ # Retrieve a list of 1st degree connections for a user who has
43
+ # granted access to his/her account
44
+ #
45
+ # Permissions: r_network
46
+ #
47
+ # @see http://developer.linkedin.com/documents/connections-api
48
+ # @macro profile_args
49
+ def connections(id={}, options={})
50
+ options = parse_id(id, options)
51
+ path = "#{profile_path(options, false)}/connections"
52
+ get(path, options)
53
+ end
54
+
55
+ # Retrieve a list of the latest set of 1st degree connections for a
56
+ # user
57
+ #
58
+ # Permissions: r_network
59
+ #
60
+ # @see http://developer.linkedin.com/documents/connections-api
61
+ #
62
+ # @param [String, Fixnum, Time] modified_since timestamp in unix time
63
+ # miliseconds indicating since when you want to retrieve new
64
+ # connections
65
+ # @param [Hash] opts profile options
66
+ # @macro profile_options
67
+ # @return [LinkedIn::Mash]
68
+ def new_connections(since, options={})
69
+ since = parse_modified_since(since)
70
+ options.merge!('modified' => 'new', 'modified-since' => since)
71
+ path = "#{profile_path(options, false)}/connections"
72
+ get(path, options)
73
+ end
74
+
75
+ # Retrieve the picture url
76
+ # http://api.linkedin.com/v1/people/~/picture-urls::(original)
77
+ #
78
+ # Permissions: r_network
79
+ #
80
+ # @options [String] :id, the id of the person for whom you want the profile picture
81
+ # @options [String] :picture_size, default: 'original'
82
+ # @options [String] :secure, default: 'false', options: ['false','true']
83
+ #
84
+ # example for use in code: client.picture_urls(:id => 'id_of_connection')
85
+ def picture_urls(options={})
86
+ picture_size = options.delete(:picture_size) || 'original'
87
+ path = "#{profile_path(options)}/picture-urls::(#{picture_size})"
88
+ get(path, options)
89
+ end
90
+
91
+
92
+ protected ############################################################
93
+
94
+
95
+ def get(path, options)
96
+ options[:"secure-urls"] = true unless options[:secure] == false
97
+ super path, options
98
+ end
99
+
100
+
101
+ private ##############################################################
102
+
103
+
104
+ def parse_id(id, options)
105
+ if id.is_a? String
106
+ if id.downcase =~ /linkedin\.com/
107
+ options[:url] = id
108
+ else
109
+ options[:id] = id
110
+ end
111
+ elsif id.is_a? Hash
112
+ options = id
113
+ else
114
+ options = {}
115
+ end
116
+
117
+ return options
118
+ end
119
+
120
+ # Returns a unix time in miliseconds
121
+ def parse_modified_since(since)
122
+ if since.is_a? ::Fixnum
123
+ if ::Time.at(since).year < 2050
124
+ # Got passed in as seconds.
125
+ since = since * 1000
126
+ end
127
+ elsif since.is_a? ::String
128
+ since = utc_parse(since)
129
+ elsif since.is_a? ::Time
130
+ since = since.to_i * 1000
131
+ end
132
+ return since
133
+ end
134
+
135
+ def utc_parse(since)
136
+ t = ::Time.parse(since)
137
+ Time.utc(t.year, t.month, t.day, t.hour, t.min, t.sec).to_i * 1000
138
+ end
139
+
140
+ end
141
+ end
@@ -1,55 +1,70 @@
1
1
  module LinkedIn
2
-
3
- module Search
2
+ # Search APIs
3
+ #
4
+ # @see https://developer.linkedin.com/documents/people-search-api
5
+ # @see https://developer.linkedin.com/documents/company-search
6
+ # @see https://developer.linkedin.com/documents/job-search-api
7
+ class Search < APIResource
8
+ # Search through People, Companies, and Jobs
9
+ #
10
+ # To search through people you need to be part of LinkedIn's Vetted
11
+ # API Access Program.
12
+ #
13
+ # @see https://developer.linkedin.com/documents/people-search-api
14
+ #
15
+ # You can use the same API to search through Companies and Jobs.
16
+ #
17
+ # @!macro search_options
18
+ # @options opts [String] :type either "people", "companies", or
19
+ # "jobs"
20
+ # @options opts [String] :keywords various keywords to search for
21
+ # @options opts [Array, Hash] :fields fields to fetch. The
22
+ # list of fields can be found at
23
+ # https://developer.linkedin.com/documents/field-selectors
24
+ # @options opts various There are many more options you can search
25
+ # by see https://developer.linkedin.com/documents/people-search-api
26
+ # for more possibilities. All keys can be entered underscored and
27
+ # they will be dasherized to match the field names on LinkedIn's
28
+ # website
29
+ #
30
+ # @overload search
31
+ # Grabs all people in your network
32
+ # @overload search(keyword_string)
33
+ # Keyword search through people
34
+ # @param [String] keywords search keywords
35
+ # @overload search(keyword_string, type)
36
+ # Keyword search through people
37
+ # @param [String] keywords search keywords
38
+ # @param [String] type either "people", "companies", or "jobs"
39
+ # @overload search(opts)
40
+ # Searches based on various options
41
+ # @param [Hash] opts search options
42
+ # @macro search_options
43
+ # @overload search(opts, type)
44
+ # Searches for a type based on various options
45
+ # @param [Hash] opts search options
46
+ # @macro search_options
47
+ # @param [String] type either "people", "companies", or "jobs"
4
48
  def search(options={}, type='people')
49
+ options, type = prepare_options(options, type)
5
50
  path = "/#{type.to_s}-search"
6
-
7
- if options.is_a?(Hash)
8
- fields = options.delete(:fields)
9
- path += field_selector(fields) if fields
10
- end
11
-
12
- options = { :keywords => options } if options.is_a?(String)
13
- options = format_options_for_query(options)
14
-
15
- result_json = get(to_uri(path, options))
16
-
17
- Mash.from_json(result_json)
51
+ get(path, options)
18
52
  end
19
53
 
20
- private
54
+ private ##############################################################
21
55
 
22
- def format_options_for_query(opts)
23
- opts.inject({}) do |list, kv|
24
- key, value = kv.first.to_s.gsub("_","-"), kv.last
25
- list[key] = sanitize_value(value)
26
- list
27
- end
56
+ def prepare_options(options, type)
57
+ options ||= {}
58
+ if options.is_a? String or options.is_a? Array
59
+ kw = options
60
+ options = {keywords: kw}
28
61
  end
29
62
 
30
- def sanitize_value(value)
31
- value = value.join("+") if value.is_a?(Array)
32
- value = value.gsub(" ", "+") if value.is_a?(String)
33
- value
63
+ if not options[:type].nil?
64
+ type = options.delete(:type)
34
65
  end
35
66
 
36
- def field_selector(fields)
37
- result = ":("
38
- fields = fields.to_a.map do |field|
39
- if field.is_a?(Hash)
40
- innerFields = []
41
- field.each do |key, value|
42
- innerFields << key.to_s.gsub("_","-") + field_selector(value)
43
- end
44
- innerFields.join(',')
45
- else
46
- field.to_s.gsub("_","-")
47
- end
48
- end
49
- result += fields.join(',')
50
- result += ")"
51
- result
52
- end
67
+ return [options, type]
68
+ end
53
69
  end
54
-
55
70
  end
@@ -0,0 +1,128 @@
1
+ module LinkedIn
2
+ # Share and Social Stream APIs
3
+ #
4
+ # @see http://developer.linkedin.com/documents/share-and-social-stream
5
+ # @see http://developer.linkedin.com/documents/share-api Share API
6
+ #
7
+ # The following API actions do not have corresponding methods in
8
+ # this module
9
+ #
10
+ # * GET Network Statistics
11
+ # * POST Post Network Update
12
+ #
13
+ # [(contribute here)](https://github.com/emorikawa/linkedin-oauth2)
14
+ class ShareAndSocialStream < APIResource
15
+ # Retrieve the authenticated users network updates
16
+ #
17
+ # Permissions: rw_nus
18
+ #
19
+ # @see http://developer.linkedin.com/documents/get-network-updates-and-statistics-api
20
+ # @see http://developer.linkedin.com/documents/network-update-types Network Update Types
21
+ #
22
+ # @macro profile_options
23
+ # @option options [String] :scope
24
+ # @option options [String] :type
25
+ # @option options [String] :count
26
+ # @option options [String] :start
27
+ # @option options [String] :after
28
+ # @option options [String] :before
29
+ # @option options [String] :show-hidden-members
30
+ # @return [LinkedIn::Mash]
31
+ def network_updates(options={})
32
+ path = "#{profile_path(options)}/network/updates"
33
+ get(path, options)
34
+ end
35
+
36
+ # TODO refactor to use #network_updates
37
+ def shares(options={})
38
+ path = "#{profile_path(options)}/network/updates"
39
+ get(path, {type: "SHAR", scope: "self"}.merge(options))
40
+ end
41
+
42
+ # Retrieve all comments for a particular network update
43
+ #
44
+ # @note The first 5 comments are included in the response to #network_updates
45
+ #
46
+ # Permissions: rw_nus
47
+ #
48
+ # @see http://developer.linkedin.com/documents/commenting-reading-comments-and-likes-network-updates
49
+ #
50
+ # @param [String] update_key a update/update-key representing a
51
+ # particular network update
52
+ # @macro profile_options
53
+ # @return [LinkedIn::Mash]
54
+ def share_comments(update_key, options={})
55
+ path = "#{profile_path(options)}/network/updates/key=#{update_key}/update-comments"
56
+ get(path, options)
57
+ end
58
+
59
+ # Retrieve all likes for a particular network update
60
+ #
61
+ # @note Some likes are included in the response to #network_updates
62
+ #
63
+ # Permissions: rw_nus
64
+ #
65
+ # @see http://developer.linkedin.com/documents/commenting-reading-comments-and-likes-network-updates
66
+ #
67
+ # @param [String] update_key a update/update-key representing a
68
+ # particular network update
69
+ # @macro profile_options
70
+ # @return [LinkedIn::Mash]
71
+ def share_likes(update_key, options={})
72
+ path = "#{profile_path(options)}/network/updates/key=#{update_key}/likes"
73
+ get(path, options)
74
+ end
75
+
76
+ # Create a share for the authenticated user
77
+ #
78
+ # Permissions: rw_nus
79
+ #
80
+ # @see http://developer.linkedin.com/documents/share-api
81
+ #
82
+ # @macro share_input_fields
83
+ # @return [void]
84
+ def add_share(share)
85
+ path = "/people/~/shares"
86
+ defaults = {visibility: {code: "anyone"}}
87
+ post(path, defaults.merge(share))
88
+ end
89
+
90
+ # Create a comment on an update from the authenticated user
91
+ #
92
+ # @see http://developer.linkedin.com/documents/commenting-reading-comments-and-likes-network-updates
93
+ #
94
+ # @param [String] update_key a update/update-key representing a
95
+ # particular network update
96
+ # @param [String] comment The text of the comment
97
+ # @return [void]
98
+ def update_comment(update_key, comment)
99
+ path = "/people/~/network/updates/key=#{update_key}/update-comments"
100
+ post(path, {comment: comment})
101
+ end
102
+
103
+ # (Update) like an update as the authenticated user
104
+ #
105
+ # @see http://developer.linkedin.com/documents/commenting-reading-comments-and-likes-network-updates
106
+ #
107
+ # @param [String] update_key a update/update-key representing a
108
+ # particular network update
109
+ # @return [void]
110
+ def like_share(update_key)
111
+ path = "/people/~/network/updates/key=#{update_key}/is-liked"
112
+ put(path, "true")
113
+ end
114
+
115
+ # (Destroy) unlike an update the authenticated user previously
116
+ # liked
117
+ #
118
+ # @see http://developer.linkedin.com/documents/commenting-reading-comments-and-likes-network-updates
119
+ #
120
+ # @param [String] update_key a update/update-key representing a
121
+ # particular network update
122
+ # @return [void]
123
+ def unlike_share(update_key)
124
+ path = "/people/~/network/updates/key=#{update_key}/is-liked"
125
+ put(path, "false")
126
+ end
127
+ end
128
+ end
@@ -1,11 +1,3 @@
1
1
  module LinkedIn
2
-
3
- module VERSION #:nodoc:
4
- MAJOR = 0
5
- MINOR = 1
6
- PATCH = 1
7
- PRE = nil
8
- STRING = [MAJOR, MINOR, PATCH, PRE].compact.join('.')
9
- end
10
-
2
+ VERSION = '1.0.0'
11
3
  end
@@ -1,32 +1,50 @@
1
- require 'oauth2'
1
+ require "oauth2"
2
+
3
+ require "linked_in/errors"
4
+ require "linked_in/version"
5
+ require "linked_in/configuration"
6
+
7
+ # Responsible for all authentication
8
+ # LinkedIn::OAuth2 inherits from OAuth2::Client
9
+ require "linked_in/oauth2"
10
+
11
+ # Coerces LinkedIn JSON to a nice Ruby hash
12
+ # LinkedIn::Mash inherits from Hashie::Mash
13
+ require "hashie"
14
+ require "linked_in/mash"
15
+
16
+ # Wraps a LinkedIn-specifc API connection
17
+ # LinkedIn::Connection inherits from Faraday::Connection
18
+ require "faraday"
19
+ require "linked_in/connection"
20
+
21
+ # Data object to wrap API access token
22
+ require "linked_in/access_token"
23
+
24
+ # Endpoints inherit from APIResource
25
+ require "linked_in/api_resource"
26
+
27
+ # All of the endpoints
28
+ require "linked_in/jobs"
29
+ require "linked_in/people"
30
+ require "linked_in/search"
31
+ require "linked_in/groups"
32
+ require "linked_in/companies"
33
+ require "linked_in/communications"
34
+ require "linked_in/share_and_social_stream"
35
+
36
+ # The primary API object that makes requests.
37
+ # It composes in all of the endpoints
38
+ require "linked_in/api"
2
39
 
3
40
  module LinkedIn
41
+ @config = Configuration.new
4
42
 
5
43
  class << self
6
- attr_accessor :client_id, :client_secret, :default_profile_fields
7
-
8
- # config/initializers/linkedin.rb (for instance)
9
- #
10
- # LinkedIn.configure do |config|
11
- # config.client_id = 'client_id'
12
- # config.client_secret = 'client_secret'
13
- # config.default_profile_fields = ['education', 'positions']
14
- # end
15
- #
16
- # elsewhere
17
- #
18
- # client = LinkedIn::Client.new
19
- def configure
20
- yield self
21
- true
22
- end
44
+ attr_accessor :config
23
45
  end
24
46
 
25
- autoload :Api, "linked_in/api"
26
- autoload :Client, "linked_in/client"
27
- autoload :Mash, "linked_in/mash"
28
- autoload :Errors, "linked_in/errors"
29
- autoload :Helpers, "linked_in/helpers"
30
- autoload :Search, "linked_in/search"
31
- autoload :Version, "linked_in/version"
47
+ def self.configure
48
+ yield self.config
49
+ end
32
50
  end