I can read and scan the files fine in a Google Drive, but I can't seem to access the web_content_link, no matter what I do. My Auth perms look fine. I'm at a complete loss.
I abstracted some of the Google Drive API logic to google_setup.rb.
And then in my rake file, all I want to do is access the download file. I seem to be able to scan through the files just fine, but even though, it looks to me like I should have perms to access the download link, I always get a 403 Forbidden error.
If you can be of any help, please let me know!
google_setup.rb
require 'google/apis/drive_v3'
require 'googleauth'
require 'googleauth/stores/file_token_store'
require 'fileutils'
require 'open-uri'
module GoogleSetup
OOB_URI = "urn:ietf:wg:oauth:2.0:oob".freeze
def self.authorize
client_id = Google::Auth::ClientId.from_file Rails.root.join('lib', 'assets', 'credentials.json').freeze
token_store = Google::Auth::Stores::FileTokenStore.new file: 'token.yaml'
authorizer = Google::Auth::UserAuthorizer.new client_id, Google::Apis::DriveV3::AUTH_DRIVE, token_store
user_id = 'default'
credentials = authorizer.get_credentials user_id
if credentials.nil?
url = authorizer.get_authorization_url base_url: 'https://seeburg.herokuapp.com/'
puts 'Open the following URL in the browser and enter the ' \
"resulting code after authorization:\n" + url
code = ENV["GOOGLE_CODE"]
credentials = authorizer.get_and_store_credentials_from_code(
user_id: user_id, code: code, base_url: OOB_URI
)
end
drive_service = Google::Apis::DriveV3::DriveService.new
drive_service.client_options.application_name = 'Seeburg Google Drive Integration'
drive_service.authorization = credentials
drive_service
end
def self.get_files(query)
drive_service = GoogleSetup.authorize
files = []
#page_token = ''
while #page_token
begin
response = drive_service.list_files(page_size: 100, q: query, page_token: #page_token, fields: 'nextPageToken, files')
#page_token = response.next_page_token || false
if response.files.empty?
puts 'No files found'
else
files = response.files
end
sleep 0.5
rescue StandardError => e
puts e
end
end
files
end
end
test_google.rake
require 'google_setup'
require 'fileutils'
require 'open-uri'
desc 'Test Google Drive API'
task test_google: :environment do
folder_id = "1j1Ly_NveiCtfrolzSxmrbHS1DenPZagV";
query = "name contains 'MP3' and '#{folder_id}' in parents";
GoogleSetup.get_files(query).each do |file|
##If I can get this section to work, everything else I need will work
begin
puts download = URI.open(file.web_content_link)
rescue StandardError => e
puts e
end
end
end
It ended up being a timeout issue. Google only lets you take certain actions within a timeframe of authentication.
Related
I am first time using Google APIs. I am unable to upload any file in Google Drive. I tried below complete code.
require 'google/apis/drive_v2'
require 'google/api_client/client_secrets'
# I downloaded 'client_secrets.json' file from 'https://console.developers.google.com/projectselector/apis/library' and put in lib folder
CLIENT_SECRETS_FILE = "client_secrets.json"
client_secrets_filepath = File.expand_path(CLIENT_SECRETS_FILE ,"#{File.dirname(__FILE__)}/../../lib/")
CLIENT_SECRETS = Google::APIClient::ClientSecrets.load(client_secrets_filepath)
authorization = CLIENT_SECRETS.to_authorization
Drive = Google::Apis::DriveV2
#drive = Drive::DriveService.new
#drive.authorization = authorization
file_path = File.expand_path(#ScreenShot_dir)+'/'+"imageName" +'.png'
metadata = Drive::File.new(title: 'My document')
metadata = #drive.insert_file(metadata, upload_source: file_path, content_type: 'image/png')
It is not uploading the file in drive but giving an error like "missing authorization code".
my client_secrets.json look like below:
{"installed":{
"client_id":"<some digits>.apps.googleusercontent.com",
"project_id":"<projectname>","auth_uri":"https://accounts.google.com/o/oauth2/auth",
"token_uri":"https://accounts.google.com/o/oauth2/token",
"auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs",
"client_secret":"<secret key>",
"redirect_uris":["urn:ietf:wg:oauth:2.0:oob","http://localhost"]}}
I am not sure what I am missing in it. Appreciate any help on this issue.
"missing authorization code"
Means that you have not properly authenticated your code.
You should check the Ouath2 documentation for the client library. Get one of the samples there working then you should be able to alter it for Drive without to much trouble.
# AdSense Management API command-line sample.
require 'google/apis/adsense_v1_4'
require 'google/api_client/client_secrets'
require 'google/api_client/auth/installed_app'
require 'google/api_client/auth/storage'
require 'google/api_client/auth/storages/file_store'
require 'logger'
require 'json'
CREDENTIAL_STORE_FILE = "#{$0}-oauth2.json"
# Handles authentication and loading of the API.
def setup
log_file = File.open('adsense.log', 'a+')
log_file.sync = true
logger = Logger.new(log_file)
logger.level = Logger::DEBUG
adsense = Google::Apis::AdsenseV1_4::AdSenseService.new
# Stores auth credentials in a file, so they survive multiple runs
# of the application. This avoids prompting the user for authorization every
# time the access token expires, by remembering the refresh token.
# Note: FileStorage is not suitable for multi-user applications.
storage = Google::APIClient::Storage.new(
Google::APIClient::FileStore.new(CREDENTIAL_STORE_FILE))
adsense.authorization = storage.authorize
if storage.authorization.nil?
client_secrets = Google::APIClient::ClientSecrets.load
# The InstalledAppFlow is a helper class to handle the OAuth 2.0 installed
# application flow, which ties in with Stroage to store credentials
# between runs.
flow = Google::APIClient::InstalledAppFlow.new(
:client_id => client_secrets.client_id,
:client_secret => client_secrets.client_secret,
:scope => ['https://www.googleapis.com/auth/adsense.readonly']
)
adsense.authorization = flow.authorize(storage)
end
return adsense
end
# Generates a report for the default account.
def generate_report(adsense)
report = adsense.generate_report(start_date: '2011-01-01', end_date: '2011-08-31',
metric: %w(PAGE_VIEWS AD_REQUESTS AD_REQUESTS_COVERAGE
CLICKS AD_REQUESTS_CTR COST_PER_CLICK
AD_REQUESTS_RPM EARNINGS),
dimension: %w(DATE),
sort: %w(+DATE))
# Display headers.
report.headers.each do |header|
print '%25s' % header.name
end
puts
# Display results.
report.rows.each do |row|
row.each do |column|
print '%25s' % column
end
puts
end
end
if __FILE__ == $0
adsense = setup()
generate_report(adsense)
end
I have a code in ruby that calls to a google apps script that create a spreadsheet report. But this generation will take more than 20 minutes( a lot of info) but after a couple of minutes I receive the message Error calling API! execution expired.
I am using the following code:
OOB_URI = 'urn:ietf:wg:oauth:2.0:oob'
APPLICATION_NAME = 'GoogleService'
SCOPE = ['https://www.googleapis.com/auth/drive', 'https://www.googleapis.com/auth/spreadsheets']
CERT_PATH = Gem.loaded_specs['google-api-client'].full_gem_path+'/lib/cacerts.pem'
ENV['SSL_CERT_FILE'] = CERT_PATH
def self.authorize
dir_path = File.dirname(__FILE__)
client_id = Google::Auth::ClientId.from_file("#{dir_path}/client_secret.json")
token_store = Google::Auth::Stores::FileTokenStore.new(file: "#{dir_path}/google_service.yaml")
authorizer = Google::Auth::UserAuthorizer.new(
client_id, SCOPE, token_store)
user_id = 'default'
credentials = authorizer.get_credentials(user_id)
if credentials.nil?
url = authorizer.get_authorization_url(
base_url: OOB_URI)
p "Open the following URL in the browser and enter the " +
"resulting code after authorization"
p url
code = gets
credentials = authorizer.get_and_store_credentials_from_code(
user_id: user_id, code: code, base_url: OOB_URI)
end
credentials
end
def self.create_spreadsheet(environment, root_path)
id_spreadsheet = nil
scrip_id = 'MerlVgs0vXonNfecv1XNrXTOzpl-Lo'
# Initialize the API
service = Google::Apis::ScriptV1::ScriptService.new
service.client_options.application_name = APPLICATION_NAME
service.authorization = self.authorize
# Create an execution request object.
request = Google::Apis::ScriptV1::ExecutionRequest.new
request.function = 'createSpreadsheet'
request.parameters = [environment, timestamp]
begin
# Make the API request.
resp = service.run_script(scrip_id, request)
if resp.error
# The API executed, but the script returned an error.
# Extract the first (and only) set of error details. The values of this
# object are the script's 'errorMessage' and 'errorType', and an array of
# stack trace elements.
error = resp.error.details[0]
puts "Script error message: #{error['errorMessage']}"
if error['scriptStackTraceElements']
# There may not be a stacktrace if the script didn't start executing.
puts "Script error stacktrace:"
error['scriptStackTraceElements'].each do |trace|
puts "\t#{trace['function']}: #{trace['lineNumber']}"
end
end
else
id_spreadsheet = resp.response['result']
end
rescue Exception => e
# The API encountered a problem before the script started executing.
puts "Error calling API!"
puts e.message
end
id_spreadsheet
end
How should I modify my code in order that the token don't expire?
I will appreciate any guide to do this thanks
Regards,
Walter
I am trying to connect to the Gmail api using the Gmail for Ruby gem. I'm following this google oauth2 guide for installed applications.
I have set my app up in the Google Developer's Console, I am able to send a request with my client_id and client_secret to obtain an authorization code. I am then able to send a request with my authorization code to obtain an access token and a refresh token. I am able to successfully send a request to refresh my access token, and it returns a new access token.
The problem arises when I try to connect to Gmail. First I set an instance variable #gmail = Gmail.connect(:xoauth2, #email, #client.access_token). Then, I attempt to login with #gmail.login(true). However, when I try that, I get the following error:
Couldn't login to given Gmail account: caiden.robinson35#gmail.com (Invalid credentials (Failure)) (Gmail::Client::AuthorizationError)
I am at a loss here, everything suggests I'm executing the oauth2 flow correctly, except the fact that when it comes time to login, I get invalid credentials. When generating my authorization code, I specifically click my email and allow my app to have access. The API is also enabled in my developers console. Here is the full code:
class GmailClient
def initialize
load_client_info
#email = "caiden.robinson35#gmail.com"
load_and_set_oauth2_tokens
sign_in_gmail
binding.pry
end
private
def sign_in_gmail
binding.pry
#gmail = Gmail.connect(:xoauth2, #email, #client.access_token)
######################
# RIGHT HERE IS WHERE IT FAIL
######################
#gmail.login true
binding.pry
end
def load_client_info
gmail_credentials = YAML.load_file('config/gmail.yml')
#client_id = gmail_credentials["client_id"]
#client_secret = gmail_credentials["client_secret"]
#redirect_uri = 'urn:ietf:wg:oauth:2.0:oob'
end
def load_and_set_oauth2_tokens use_cached_tokens = true
if use_cached_tokens && File.exist?("config/tokens.yml")
token_hash = YAML.load_file('config/tokens.yml')
#authorization_code = { code: token_hash["authorization_code"],
is_cached: true }
#client = signet_client(token_hash)
#token_hash = #client.refresh!
else
if !(instance_variable_defined?("#authorization_code") && #authorization_code[:is_cached] == false)
retrieve_and_set_authorization_code
end
#token_hash = set_client_and_retrieve_oauth2_tokens
end
write_tokens_to_file
end
def retrieve_and_set_authorization_code
puts "Go to the following url to enable the gmail cli app:"
puts "https://accounts.google.com/o/oauth2/auth?scope=email&redirect_uri=urn:ietf:wg:oauth:2.0:oob&response_type=code&client_id=#{#client_id}"
print "Paste your authorization code here: "
#authorization_code = { code: gets.chomp,
is_cached: false }
end
def set_client_and_retrieve_oauth2_tokens
#client = signet_client
#client.fetch_access_token!
end
def signet_client token_hash = nil
client = Signet::OAuth2::Client.new(
client_id: #client_id,
client_secret: #client_secret,
redirect_uri: #redirect_uri,
scope: 'email',
token_credential_uri: 'https://www.googleapis.com/oauth2/v4/token'
)
if token_hash.present?
client.refresh_token = token_hash["refresh_token"]
else
client.authorization_uri = 'https://accounts.google.com/o/oauth2/auth'
client.code = #authorization_code[:code]
end
client
end
def write_tokens_to_file
if File.exist?("config/tokens.yml")
data = YAML.load_file "config/tokens.yml"
#token_hash.each { |k, v| data[k] = v }
File.open('config/tokens.yml', 'w') do |file|
YAML.dump(data, file)
end
else
File.open('config/tokens.yml', 'w') do |file|
#token_hash.each { |k, v| file.write("#{k}: #{v}\n") }
file.write("authorization_code: #{#authorization_code[:code]}\n")
end
end
end
end
If my question is lacking any info, please just ask, I am eager to solve this.
Scopes matter. Here are right ones:
scope: ['https://mail.google.com/', 'https://www.googleapis.com/auth/userinfo.email' #,'https://www.googleapis.com/auth/gmail.send' - if you'd like to send emails as well]
I am trying to setup a command line backup app in ruby which accesses Google Drive using Oauth. I have set everything up in the account, created my Client ID and Secret. I seem to remember doing this before but cannot find the code. I used this answer before I think: Ruby google_drive gem oAuth2 saving
I have made a class to handle the Google Drive stuff then there is the applications main file which if given "hard" as an argument will do the initial setup where you have to copy and paste the link into the web browser in order to get a code which you can then paste into the CLI to get the initial access token and refresh token. This works and following these steps my list method (when not commented out) correctly lists everything in Google Drive. When I do the initial setup I am manually copying the access and refresh tokens to .access_token and .refresh_token, these are loading in the code fine.
What is not working, is refreshing the token which I understand I need to do otherwise it will expire, meaning I will have to go through the initial setup again which is obviously a pain (and not suitable for a CRON job). I am getting the following error when I run #auth.refresh!
/home/user/.rvm/gems/ruby-2.2.0/gems/signet-0.6.0/lib/signet/oauth_2/client.rb:947:in `fetch_access_token': Authorization failed. Server message: (Signet::AuthorizationError)
{
"error" : "invalid_grant"
}
from /home/user/.rvm/gems/ruby-2.2.0/gems/signet-0.6.0/lib/signet/oauth_2/client.rb:964:in `fetch_access_token!'
from /home/user/.rvm/gems/ruby-2.2.0/gems/signet-0.6.0/lib/signet/oauth_2/client.rb:981:in `refresh!'
from /home/user/Development/BackupBadger/Sources/Mechanisms/GoogleDriveMechanism.rb:62:in `connect'
from BackupBadger.rb:9:in `<main>'
I have had a look to see what it might be but am for the moment stuck on why this error is triggering when I can seemingly authenticate (since I can list all files on the drive)
My main file
$root=File.join('/home/user/Development/BackupBadger')
$sources=File.join($root,'Sources')
require File.join($sources,'Mechanisms','GoogleDriveMechanism.rb')
badger = BackupBadger::GoogleDriveMechanism.new
if ARGV[0] == "hard" then
badger.hard_setup
else
badger.connect
#badger.list
end
My class Google Drive
module BackupBadger
require 'google/api_client'
require 'google_drive'
require 'pp'
require File.join($sources,'Mechanism.rb')
class GoogleDriveMechanism
def initialize()
#client = Google::APIClient.new(
:application_name => 'Backup Badger',
:application_version => '0.0.1'
)
#access_token_path = File.join($root,'.access_token')
#refresh_token_path = File.join($root,'.refresh_token')
#auth = nil
#access_token = File.open(#access_token_path, "rb").read
#refresh_token = File.open(#refresh_token_path, "rb").read
#session = nil
#client_id = 'CLIENT_ID'
#client_secret = 'CLIENT_SECRET'
#redirect_uri = 'urn:ietf:wg:oauth:2.0:oob'
#scope = "https://www.googleapis.com/auth/drive " +
"https://spreadsheets.google.com/feeds/"
end
# Call this to do the initial setup, which requires pasting a url into a web broswer
def hard_setup
#auth = #client.authorization
#auth.client_id = #client_id
#auth.client_secret = #client_secret
#auth.scope = #scope
#auth.redirect_uri = #redirect_uri
print("1. Open this page:\n%s\n\n" % #auth.authorization_uri)
print("2. Enter the authorization code shown in the page: ")
#auth.code = $stdin.gets.chomp
#auth.fetch_access_token!
#access_token = #auth.access_token
system'clear'
print "Save your access token\n\n"
print #access_token
print "\nSave your refresh token\n\n"
print #auth.refresh_token
end
def connect
#auth = #client.authorization
#auth.client_id = #client_id
#auth.client_secret = #client_secret
#auth.scope = #scope
#auth.redirect_uri = #redirect_uri
#auth.refresh_token = #refresh_token
puts #access_token
puts #refresh_token
# Error is here
#auth.refresh!
#refresh_token = #auth.refresh_token
#access_token = #auth.access_token
File.write(#refresh_token_path, #refresh_token) if #refresh_token
File.write(#access_token_path, #access_token) if #access_token
puts #access_token
puts #refresh_token
end
def list
#session = GoogleDrive.login_with_oauth(#access_token)
for file in #session.files
p file.title
end
end
end
end
If the tl;dr is simply "how do I use a refresh token to get a new access token", then the answer is https://developers.google.com/accounts/docs/OAuth2WebServer#refresh
I won't paste the code coz it's likely to change, but in essence you simply POST to a Google URL and the JSON response is a shiny new access token.
I have written a script in ruby that navigates through a website and gets to a form page. Once the form page is filled out the script hits the submit button and then a dialogbox opens asking you where to save it too. I am having trouble trying to get this file. I have searched the web and cant find anything. How would i go about retrieveing the file name of the document?
I would really appreciate if someone could help me
My code is below:
browser = Mechanize.new
## CONSTANTS
LOGIN_URL = 'https://business.airtricity.com/ews/welcome.jsp'
HOME_PAGE_URL = 'https://business.airtricity.com/ews/welcome.jsp'
CONSUMPTION_REPORT_URL = 'https://business.airtricity.com/ews/touConsChart.jsp?custid=209495'
LOGIN = ""
PASS = ""
MPRN_GPRN_LCIS = "10000001534"
CONSUMPTION_DATE = "20/01/2013"
END_DATE = "27/01/2013"
DOWNLOAD = "DL"
### Login page
begin
login_page = browser.get(LOGIN_URL)
rescue Mechanize::ResponseCodeError => exception
login_page = exception.page
end
puts "+++++++++"
puts login_page.links
puts "+++++++++"
login_form = login_page.forms.first
login_form['userid'] = LOGIN
login_form['password'] = PASS
login_form['_login_form_'] = "yes"
login_form['ipAddress'] = "137.43.154.176"
login_form.submit
## home page
begin
home_page = browser.get(HOME_PAGE_URL)
rescue Mechanize::ResponseCodeError => exception
home_page = exception.page
end
puts "----------"
puts home_page.links
puts "----------"
# Consumption Report
begin
Report_Page = browser.get(CONSUMPTION_REPORT_URL)
rescue Mechanize::ResponseCodeError => exception
Report_Page = exception.page
end
puts "**********"
puts Report_Page.links
pp Report_Page
puts "**********"
Report_Form = Report_Page.forms.first
Report_Form['entity1'] = MPRN_GPRN_LCIS
Report_Form['start'] = CONSUMPTION_DATE
Report_Form['end'] = END_DATE
Report_Form['charttype'] = DOWNLOAD
Report_Form.submit
## Download Report
begin
browser.pluggable_parser.csv = Mechanize::Download
Download_Page = browser.get('https://business.airtricity.com/ews/touConsChart.jsp?custid=209495/meter_read_download_2013-1-20_2013-1-27.csv').save('Hello')
rescue Mechanize::ResponseCodeError => exception
Download_Page = exception.page
end
http://mechanize.rubyforge.org/Mechanize.html#method-i-get_file
File downloading from url it's pretty straightforward with mechanize:
browser = Mechanize.new
file_url = 'https://raw.github.com/ragsagar/ragsagar.github.com/c5caa502f8dec9d5e3738feb83d86e9f7561bd5e/.html'
downloaded_file = browser.get_file file_url
File.open('new_file.txt', 'w') { |file| file.write downloaded_file }
I've seen automation fail because of the browser agent. Perhaps you could try
browser.user_agent_alias = "Windows Mozilla"