-
Notifications
You must be signed in to change notification settings - Fork 407
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Update LinkedIn::Api::ShareAndSocialStream#add_share for Api v2 #274
base: master
Are you sure you want to change the base?
Changes from all commits
1380065
2a7e4bf
6a0c254
7a487df
b7fdad9
68eee85
299840f
f45a6d4
ea4b000
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
module LinkedIn | ||
module Api | ||
|
||
# V2 Consumer API | ||
# | ||
# @see https://docs.microsoft.com/en-us/linkedin/consumer/ | ||
module V2 | ||
|
||
# Obtain profile information for a member. Currently, the method only | ||
# accesses the authenticated user. | ||
# | ||
# Permissions: r_liteprofile r_emailaddress | ||
# | ||
# @see https://docs.microsoft.com/en-us/linkedin/consumer/integrations/self-serve/sign-in-with-linkedin?context=linkedin/consumer/context#retrieving-member-profiles | ||
# | ||
# @return [void] | ||
def v2_profile | ||
path = '/me' | ||
v2_get(path) | ||
end | ||
|
||
# Share content for the authenticated user | ||
# | ||
# Permissions: w_member_share | ||
# | ||
# @see https://docs.microsoft.com/en-us/linkedin/consumer/integrations/self-serve/share-on-linkedin | ||
# | ||
# @param [String] urn User's URN (UID) returned from OAuth access token | ||
# request | ||
# @param [Hash] share The body we want to submit to LinkedIn. At least a | ||
# comment is required | ||
# | ||
# @macro share_input_fields | ||
# @return [void] | ||
def v2_add_share(urn, share = {}) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Again with the same nitpick. I feel like if it is already scoped to a V2 module it should just be without a prefix on the method. |
||
if !urn.instance_of?(String) || urn.empty? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think that really what you're after is something like this: (urn.respond_to?(:empty?) && urn.empty?) || !urn |
||
raise LinkedIn::Errors::UnavailableError, 'LinkedIn API: URN required' | ||
elsif share[:comment].nil? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this will be safer !share.fetch(:comment, false) |
||
raise LinkedIn::Errors::UnavailableError, | ||
'LinkedIn API: Comment required' | ||
end | ||
|
||
path = '/ugcPosts' | ||
v2_post(path, MultiJson.dump(share_payload(urn, share))) | ||
end | ||
|
||
private | ||
|
||
def share_payload(urn, share) | ||
payload = { author: "urn:li:person:#{urn}", | ||
lifecycleState: 'PUBLISHED', | ||
visibility: { | ||
'com.linkedin.ugc.MemberNetworkVisibility' => 'PUBLIC' | ||
} | ||
} | ||
|
||
return add_url_to_payload(payload, share) if share[:url] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is a nitpick of mine. I would prefer it to look something more like if share.has_key?(:url)
add_url_to_payload(payload, share)
else
add_comment_to_payload(payload,share)
end There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. also I think if !!share.fetch(:url, false)
...
end |
||
|
||
add_comment_to_payload(payload, share) | ||
end | ||
|
||
def add_url_to_payload(payload, share) | ||
media = { status: 'READY', originalUrl: share[:url] } | ||
if share[:description] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. these are tough because we are checking if they are in the hash, but should we be checking for things like blankness? |
||
media[:description] = { text: share[:description] } | ||
end | ||
if share[:title] | ||
media[:title] = { text: share[:title] } | ||
end | ||
payload[:specificContent] = { | ||
'com.linkedin.ugc.ShareContent' => { | ||
shareCommentary: { text: share[:comment] }, | ||
shareMediaCategory: 'ARTICLE', | ||
media: [media] | ||
} | ||
} | ||
payload | ||
end | ||
|
||
def add_comment_to_payload(payload, share) | ||
payload[:specificContent] = { | ||
'com.linkedin.ugc.ShareContent' => { | ||
shareCommentary: { text: share[:comment] }, | ||
shareMediaCategory: 'NONE' | ||
} | ||
} | ||
payload | ||
end | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,13 +5,15 @@ module LinkedIn | |
class Client | ||
include Helpers::Request | ||
include Helpers::Authorization | ||
include Helpers::V2Request | ||
include Api::QueryHelpers | ||
include Api::People | ||
include Api::Groups | ||
include Api::Companies | ||
include Api::Jobs | ||
include Api::ShareAndSocialStream | ||
include Api::Communications | ||
include Api::V2 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oh I see why you prefixed the methods now... hmmm... well I suppose that's ok it just feels a bit awkward to me is all. |
||
include Search | ||
|
||
attr_reader :consumer_token, :consumer_secret, :consumer_options | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
module LinkedIn | ||
module Helpers | ||
|
||
module V2Request | ||
|
||
DEFAULT_HEADERS = { | ||
'x-li-format' => 'json', | ||
'Content-Type' => 'application/json', | ||
'X-Restli-Protocol-Version' => '2.0.0' | ||
} | ||
|
||
API_PATH = '/v2' | ||
|
||
protected | ||
|
||
def v2_get(path, options = {}) | ||
response = access_token.get("#{API_PATH}#{path}", | ||
headers: DEFAULT_HEADERS.merge(options)) | ||
raise_errors(response) | ||
response.body | ||
end | ||
|
||
def v2_post(path, body = '', options = {}) | ||
options = { body: body, headers: DEFAULT_HEADERS.merge(options) } | ||
# response is OAuth2::Response | ||
# response.response is Faraday::Response | ||
# sending back response.response makes it easier to access the env | ||
response = access_token.post("#{API_PATH}#{path}", options).response | ||
raise_errors(response) | ||
response | ||
end | ||
|
||
private | ||
|
||
def raise_errors(response) | ||
# Even if the json answer contains the HTTP status code, LinkedIn also sets this code | ||
# in the HTTP answer (thankfully). | ||
case response.status.to_i | ||
when 401 | ||
data = Mash.from_json(response.body) | ||
raise LinkedIn::Errors::UnauthorizedError.new(data), "(#{data.status}): #{data.message}" | ||
when 400 | ||
data = Mash.from_json(response.body) | ||
raise LinkedIn::Errors::GeneralError.new(data), "(#{data.status}): #{data.message}" | ||
when 403 | ||
data = Mash.from_json(response.body) | ||
raise LinkedIn::Errors::AccessDeniedError.new(data), "(#{data.status}): #{data.message}" | ||
when 404 | ||
raise LinkedIn::Errors::NotFoundError, "(#{response.status}): #{response.message}" | ||
when 500 | ||
raise LinkedIn::Errors::InformLinkedInError, "LinkedIn had an internal error. Please let them know in the forum. (#{response.status}): #{response.message}" | ||
when 502..503 | ||
raise LinkedIn::Errors::UnavailableError, "(#{response.status}): #{response.message}" | ||
end | ||
end | ||
|
||
|
||
# Stolen from Rack::Util.build_query | ||
def to_query(params) | ||
params.map { |k, v| | ||
if v.class == Array | ||
to_query(v.map { |x| [k, x] }) | ||
else | ||
v.nil? ? escape(k) : "#{CGI.escape(k.to_s)}=#{CGI.escape(v.to_s)}" | ||
end | ||
}.join("&") | ||
end | ||
|
||
def to_uri(path, options) | ||
uri = URI.parse(path) | ||
|
||
if options && options != {} | ||
uri.query = to_query(options) | ||
end | ||
uri.to_s | ||
end | ||
end | ||
|
||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nitpick:
def profile
since it's already scoped to V2