can't download file from google drive with ruby - ruby-on-rails

I'm trying to get my rails controller set up to download a file from google drive following the code at - https://developers.google.com/drive/v2/reference/files/get
I have the following rails code
def download_file(client, file)
if file.download_url
result = client.execute(:uri => file.download_url)
if result.status == 200
return result.body
else
puts "An error occurred: #{result.data['error']['message']}"
return nil
end
end
end
def attachExternalResume
# read remote url to file
file_id = params[:fileId]
client = Google::APIClient.new
drive = client.discovered_api('drive', 'v2')
result = client.execute(
:api_method => drive.files.get,
:parameters => { 'fileId' => file_id}
)
if (result.status == 200)
p download_file client, result.data
end
end
This is being called from my javascript front end using the google picker. The user authorizes my app through the google picker and selects a file which results in my angular javascript posting the file id to my rails method. In the rails code I'm getting the following error - Missing access token.
It seems like even though the user has authorized the app on the front end, that authorization isn't making its way through to the rails side. Anyone know how I can get the authorization all the way through the process?

"I'm getting the following error - Missing access token." probably means that you're missing an access token. In the code snippet you posted, I can't see anywhere where you request an access token, so that makes it even more likely. I don't know enough about the Google Ruby library to give you the code you're missing, but look for something that takes scope(s) and application/client ID as arguments.

Related

How to access AWS Comprehend using aws-sdk-comprehend gem?

I'm working on getting my Rails app interacting with the AWS Comprehend service for text entity extraction. I'm using the aws-sdk-comprehend gem. I have successfully gotten my app working with the AWS Rekognition service for image analysis using the aws-sdk-rekognition gem.
I can't seem to get the AWS Comprehend authentication correct as all of my calls result in an Aws::Comprehend::Errors::InvalidRequestException.
I have all of the following ENV variables set:
AWSAccessKeyId
AWSSecretKey
AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY
My code looks something like this:
class MyApp::Aws::ComprehendService < MyApp::ServiceBase
def call
#credentials = Aws::Credentials.new(ENV['AWSAccessKeyId'], ENV['AWSSecretKey'])
#client = Aws::Comprehend::Client.new(region: "us-west-1", credentials: credentials)
#client.detect_entities({text: "this is a simply little blob of text", language_code: "en"})
end
end
This resulted in Aws::Comprehend::Errors::InvalidRequestException. So I also tried:
class MyApp::Aws::ComprehendService < MyApp::ServiceBase
def call
# use ENV credential format I've seen in examples...
#credentials = Aws::Credentials.new(ENV['AWS_ACCESS_KEY_ID'], ENV['AWS_SECRET_ACCESS_KEY'])
#client = Aws::Comprehend::Client.new(region: "us-west-1", credentials: credentials)
#client.detect_entities({text: "this is a simply little blob of text", language_code: "en"})
end
end
I found an example that didn't use the #credential approach. The example claimed "The initialize method will load the credentials environment variables by itself". So I tried this:
class MyApp::Aws::ComprehendService < MyApp::ServiceBase
def call
# ignore setting the credentials
#client = Aws::Comprehend::Client.new(region: "us-west-1")
#client.detect_entities({text: "this is a simply little blob of text", language_code: "en"}).
end
end
This also resulted in Aws::Comprehend::Errors::InvalidRequestException.
Can you see anything I'm doing wrong? Has anyone had success in using this gem to interact with the Comprehend API?
Per the Documentation for Aws::Comprehend::Client#detect_entities
If the system detects a document-level error in your input document, the API returns an InvalidRequestException error response. For details about this exception, see Errors in semi-structured documents in the Comprehend Developer Guide.
So it appears your usage is not necessarily the issue but rather the input documents themselves.
The response however should include what the actual issue is according to the Developer Guide:
Document-level errors
If the ClassifyDocument or DetectEntities API operation detects a document-level error in your input document, the API returns an InvalidRequestException error response.
In the error response, the Reason field contains the value INVALID_DOCUMENT.
The Detail field contains one of the following values:
DOCUMENT_SIZE_EXCEEDED – Document size is too large. Check the size of your file and resubmit the request.
UNSUPPORTED_DOC_TYPE – Document type is not supported. Check the file type and resubmit the request.
PAGE_LIMIT_EXCEEDED – Too many pages in the document. Check the number of pages in your file and resubmit the request.
TEXTRACT_ACCESS_DENIED_EXCEPTION – Access denied to Amazon Textract. Verify that your account has permission to use the Amazon Textract DetectDocumentText and AnalyzeDocument API operations and resubmit the request.
The Aws::Comprehend::Errors::InvalidRequestException object is documented so it appears you could potentially figure out what is wrong via
def call
# use ENV credential format I've seen in examples...
#credentials = Aws::Credentials.new(ENV['AWS_ACCESS_KEY_ID'], ENV['AWS_SECRET_ACCESS_KEY'])
#client = Aws::Comprehend::Client.new(region: "us-west-1", credentials: credentials)
begin
#client.detect_entities({text: "this is a simply little blob of text", language_code: "en"})
rescue Aws::Comprehend::Errors::InvalidRequestException => e
# interrogate the error object here e.g.
puts {reason: e.reason, detail: e.detail}
end
end

Rails - gem instagram - issues on access token and sandbox

I need to put on a website the complete instagram feed of my customer. I have tried several ways to access to instagram and get the whole feed, but I get some errors.
Using the gem "instagram" (the easiest and simplest method) i got the following error when I try to get the access token.
Instagram::BadRequest: POST https://api.instagram.com/oauth/access_token/: 400: OAuthException: Matching code was not found or was already used.
I tried to follow the indication on the instagram documentation https://www.instagram.com/developer/authentication/ using my browser and I can get the access token, but I am not able to do the http calls manually in ruby.
I need to download all the data and keep it inside my database (as I always done) so I need everything in the controller.
my code is very simple:
accessToken = Instagram.get_access_token(Instagram.client_id, :redirect_uri => CALLBACK_URL)
client = Instagram.client(access_token: accessToken)
response = client.user_recent_media
#other code to cycle inside posts and put everything in db
i'm sure to have included the same redirect_url in my instragram registration app and in my code.
As shown in the sample application in the gem's repo, you will need to call authorize_url first:
Instagram.authorize_url(:redirect_uri => CALLBACK_URL)
and then you will get request on the CALLBACK_URL, where you should have an action with the code that you provided:
response = Instagram.get_access_token(params[:code], :redirect_uri => CALLBACK_URL)
client = Instagram.client(:access_token => response.access_token)
# do stuff with the client
SOLVED!
I have misunderstood the usage of the api.
I got my access token following this https://elfsight.com/blog/2016/05/how-to-get-instagram-access-token/
and i can access my posts using in my model:
access_token = Instagram.access_token
client = Instagram.client(access_token: access_token)
response = client.user_recent_media
and in my config file:
Instagram.configure do |config|
config.client_id = "CLIENT_ID"
config.client_secret = "CLIENT_SECRET"
config.access_token = "ACCESS_TOKEN"
end
thanks a lot for your support
you should get the token when processing the callback in the omniauth.auth hash: request.env['omniauth.auth']['credentials']['token']

First Google Drive API files.list request returning an array of Hashes, after that, subsequent requests returning an array of File Resources. Why?

I'm querying the Google API to list all files in the drive using the Google API official gem for ruby. I'm using the example given in the Google developers page - https://developers.google.com/drive/v2/reference/files/list
The first request I made returns in the "items" an array of ruby "Hashes". The next requests return in the "items" an array of either "Google::APIClient::Schema::Drive::V2::File" or "Google::APIClient::Schema::Drive::V2::ParentReference" (the reason behind each type also buggs me).
Does anyone know why this happens? At the reference page of "files.list" none is said about changing the type of the results.
def self.retrieve_all_files(client)
drive = client.discovered_api('drive', 'v2')
result = Array.new
page_token = nil
begin
parameters = {}
if page_token.to_s != ''
parameters['pageToken'] = page_token
end
api_result = client.execute(
:api_method => drive.files.list,
:parameters => parameters)
if api_result.status == 200
files = api_result.data
result.concat(files.items)
page_token = files.next_page_token
else
puts "An error occurred: #{result.data['error']['message']}"
page_token = nil
end
end while page_token.to_s != ''
result
end
EDIT:
I couldn't solve the problem yet, but I manage to understand it better:
When the first request to the API is made, after the authorization is granted by the user, the "file.list" returns an array of Hashes at "Items" attribute of the File resource. Each of this Hashes is like a File resource, with all the attributes of the File, the difference is just in the type of the access. For example: the title of the file can be accessed like this "File['title']".
After the first request is made, all the subsequent requests return an array of File resources, that can be accessed like this "File.title".
FYI, this was a bug in the client lib. Using the latest version should fix it.

Linkedin Oauth with Rails

We have been connecting to Linkedin for awhile now successfully. However, we get some errors from time to time and I'm hoping someone can help shed some light on this. Here's our code:
def linkedin_login
request_token = Linkedin.client.request_token(oauth_callback: "http://#{SITE_URL}/linkedin/auth/")
session[:linkedin_request_token] = request_token.token
session[:linkedin_request_secret] = request_token.secret
redirect_to request_token.authorize_url
end
def linkedin_auth
raise "Don't have proper session or oauth_verifier" if session[:linkedin_request_token].blank? or session[:linkedin_request_secret].blank? or params[:oauth_verifier].blank?
access_token = Linkedin.client.authorize_from_request(session[:linkedin_request_token], session[:linkedin_request_secret], params[:oauth_verifier])
raise "Nil access token" if access_token.blank?
redirect_to linkedin_process_path(token: access_token.first, secret: access_token.second)
end
We're hitting the "raise 'Don't have proper session or oauth_verifier'" more than I would expect. When looking at the ENV for the errors, those people don't have the session values set from the original method. We have before_filters set on the application controller so initialize the session, so I know it's active.
My next thought was whether "request_token" was generating a value request_token, and I've tried many times and they all bring something back. We get many of these a day. After the error, if the user tries again, it works fine, which is why I'm so confused.
any thoughts on what could cause this?
Based on your code, it looks like you're making the request token call every time the user logs into your application. That's not the proper method to authenticate. You really only need to fetch the request token once, then use that to upgrade for an access token (as you're doing in your linkedin_auth method). From there, just save the access token and secret in your DB and fetch it anytime you need to make an API call for that particular user.
Our authentication is described more in detail here: https://developer.linkedin.com/documents/authentication
Also, this is just a personal preference, but I like using the OAuth gem for Rails as opposed to using a LinkedIn wrapper. It's easy to use and light weight.
Just as an example, you could do your auth this way:
require 'oauth'
def auth
api_key = 'XXXXXXXXX'
api_secret = 'XXXXXXXXX'
configuration = { :site => 'https://api.linkedin.com',
:authorize_path => 'https://www.linkedin.com/uas/oauth/authenticate',
:request_token_path => 'https://api.linkedin.com/uas/oauth/requestToken',
:access_token_path => 'https://api.linkedin.com/uas/oauth/accessToken' }
consumer = OAuth::Consumer.new(api_key, api_secret, configuration)
#Request token
request_token = consumer.get_request_token
# Output request URL to console
puts "Please visit this URL: https://api.linkedin.com/uas/oauth/authenticate?oauth_token=" + request_token.token + " in your browser and then input the numerical code you are provided here: "
# Set verifier code
verifier = $stdin.gets.strip
# Retrieve access token object
#access_token = request_token.get_access_token(:oauth_verifier => verifier)
end
You would only need to invoke this method when the user first authorizes your app. Save their access token then use it for subsequent API calls. Note, my example makes use of the console to enter the PIN verifier. In a real world example you'd want to programmatically save the PIN in a session variable or in memory, then use it to get the access token.

Rails EOF Error when using HTTP.get_response to retrieve Facebook access token

I trying to implement a Login with Facebook feature on my site, and hitting a roadblock trying to get the access token back from Facebook. Here is my code:
if params[:error_reason] == "user_denied" then
flash[:error] = "To login with Facebook, you must click 'Allow' to let the site access your information"
redirect_to :login
elsif params[:code] then
token_uri = URI.parse("https://graph.facebook.com/oauth/access_token?client_id=****************&redirect_uri=http://localhost:3000/auth/fblogin&client_secret=***************&code="+URI.escape(params[:code]))
response = Net::HTTP.get_response(token_uri)
session[:response] = response
data = ActiveSupport::JSON.decode(response)
access_token = data[:access_token]
flash[:error] = access_token
redirect_to :register
end
This is inside a fblogin controller function that is the target of the initial redirect to get an authorization code (the params[:code]).
But when I run through this, I get the following error:
EOFError in AuthController#fblogin
on the Net::HTTP.get_response(token_uri) line. I've searched all over, and can't find anything to indicate what this means. Could it be the obscure characters Facebook uses in their access tokens? I'm totally lost!
You are receiving an EOFError because you are trying to connect to an https URL using code that only works with http. See the section entitled "SSL/HTTPS request" at this Net::HTTP Cheat Sheet for the basics.
However, I would recommend using a third-party library to manage this for you, such as OAuth2 for utilizing Facebook's OAuth2 API, where you'd write code like this:
def client
OAuth2::Client.new('app_id', 'app_secret', :site => 'https://graph.facebook.com')
end
# in your callback code:
access_token = client.web_server.get_access_token(params[:code], :redirect_uri => 'http://localhost:3000/auth/fblogin')
user = JSON.parse(access_token.get('/me'))
If you really want to make the requests yourself, you can look at libraries like Faraday to execute the HTTPS requests for you.

Resources