linkedin-oauth2 0.1.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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