client = Twitter::REST::Client.new do |config|
config.consumer_key = "XX"
config.consumer_secret = "XY"
config.access_token = "ZZ"
config.access_token_secret = "ZZZ"
end
How can I retrieve my profile information?
You can do the following simple steps to use the Twitter client gem:
# get user id from user name
id = client.user( 'user_name' ).id
# read user's timeline by id
timeline = client.user_timeline id
# read user's timeline of yours
your_timeline = client.user_timeline
you can omit the username, and you get the timeline of current user, so try also to issue:
user_info = client.user
Related
So MS disabled IMAP for basic auth as we all know.
I am trying to figure out how to get the OAUTH 2.0 working using ruby (not ruby on rails).
I have Azure APP and everything needed (I think), but I can not find any code related to ruby and getting the access token.
First step is completed, but next step is to get the access token.
https://learn.microsoft.com/en-us/exchange/client-developer/legacy-protocols/how-to-authenticate-an-imap-pop-smtp-application-by-using-oauth
I need to read different Outlook mailboxes.
Could someone please explain how to do this?
SOLUTION for me!
Steps I took.
Made an Azure app ('Device Flow' was the easiest way to go for me) Check the Steps in the link. You also need to change some settings in your APP if you want to use IMAP. See the youtube link here between 2:50 - 4:30
Get the postman requests from this link (scroll down a little) (click here)
From postman you can use "Device Flow" requests.
Start with Device Authorization Request (you need a scope and client_id for this) I used https://outlook.office.com/IMAP.AccessAsUser.All scope.
go to the link that you got back from the request and enter the required code.
now go to Device Access Token Request and use the "device_code" from the last request and put that under code, under body.
You should get an access_token
Connect using ruby
require 'gmail_xoauth' # MUST HAVE! otherwise XOAUTH2 auth wont work
require 'net/imap'
imap = Net::IMAP.new(HOST, PORT, true)
access_token = "XXXXX"
user_name = "email#outlook.com"
p imap.authenticate('XOAUTH2',"#{user_name}", "#{access_token}")
# example
imap.list('','*').each do |folders|
p folders
end
XOAUTH2 Returns
#<struct Net::IMAP::TaggedResponse tag="RUBY0001", name="OK", data=#<struct Net::IMAP::ResponseText code=nil, text="AUTHENTICATE completed.">, raw_data="RUBY0001 OK AUTHENTICATE completed.\r\n
Just to specify
HOST = 'outlook.office365.com'
PORT = 993
UPDATE 25.01.2023
class Oauth2
require 'selenium-webdriver'
require 'webdrivers'
require 'net/http'
# Use: Oauth2.new.get_access_code
# Grants access to Office 365 emails.
def get_access_code
p "### Access Request Started #{Time.now} ###"
begin
codes = device_auth_request
authorize_device_code(codes[:user_code])
access_code = device_access_token(codes[:device_code])
access_code
rescue => e
p e
p "Something went wrong with authorizing"
end
end
def device_auth_request # Returns user_code and device_code
url = URI('https://login.microsoftonline.com/organizations/oauth2/v2.0/devicecode')
https = Net::HTTP.new(url.host, url.port)
https.use_ssl = true
request = Net::HTTP::Post.new(url)
request.body = "client_id=YOUR_CLIENT_ID&scope=%09https%3A%2F%2Foutlook.office.com%2FIMAP.AccessAsUser.All"
response = https.request(request)
{
user_code: JSON.parse(response.read_body)["user_code"],
device_code: JSON.parse(response.read_body)["device_code"]
}
end
def device_access_token(device_code)
url = URI('https://login.microsoftonline.com/organizations/oauth2/v2.0/token')
https = Net::HTTP.new(url.host, url.port)
https.use_ssl = true
request = Net::HTTP::Post.new(url)
request.body = "grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Adevice_code&code=#{device_code}&client_id=YOUR_CLIENT_ID"
response = https.request(request)
JSON.parse(response.read_body)["access_token"]
end
def authorize_device_code(device_code)
# SELENIUM SETUP
driver = setup_selenium
driver.get "https://microsoft.com/devicelogin"
sleep(4)
# ------------------------------------------
# Give Access
element = driver.find_element(:class, "form-control")
element.send_keys(device_code)
sleep(2)
element = driver.find_element(:id, "idSIButton9")
element.submit
sleep(2)
element = driver.find_element(:id, "i0116")
element.send_keys("YOUR OUTLOOK ACCOUNT EMAIL")
sleep(2)
element = driver.find_element(:class, "button_primary")
element.click
sleep(2)
element = driver.find_element(:id, "i0118")
element.send_keys("YOUR OUTLOOK PASSWORD")
element = driver.find_element(:class, "button_primary")
element.click
sleep(2)
element = driver.find_element(:class, "button_primary")
element.click
sleep(2)
# ------------------------------------------
driver.quit
end
def setup_selenium
require 'selenium-webdriver'
# set up Selenium
options = Selenium::WebDriver::Chrome::Options.new(
prefs: {
download: {
prompt_for_download: false
},
plugins: {
'always_open_pdf_externally' => true
}
}
)
options.add_argument('--headless')
options.add_argument('--no-sandbox')
# options.add_argument('-incognito')
options.add_argument('disable-popup-blocking')
Selenium::WebDriver.for :chrome, options: options
end
end
So before the update there was a simple way to log into google drive and manipulate your google docs - with ruby.
Before you were able to log into your google drive with this.
require 'google_drive'
$session = GoogleDrive.login("email#gmail.com", "password")
But now you get the warning message:
WARNING: GoogleDrive.login is deprecated and will be removed in the next version. Use GoogleDrive.login_with_oauth instead.
So I went to the git hub page to see how google wants us to use their services with high level languages, and found out they want us to use oAuth2. Like so.
require 'google/api_client'
require 'google_drive'
client = Google::APIClient.new(
:application_name => 'Example Ruby application',
:application_version => '1.0.0'
)
auth = client.authorization
auth.client_id = "YOUR CLIENT ID"
auth.client_secret = "YOUR CLIENT SECRET"
auth.scope =
"https://www.googleapis.com/auth/drive " +
"https://spreadsheets.google.com/feeds/"
auth.redirect_uri = "urn:ietf:wg:oauth:2.0:oob"
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
$session = GoogleDrive.login_with_oauth(access_token)
This is fine and all but I can't save the auth variable.
I would like to hard code this in the script so I don't have to keep going to google to get a new access_token.
So I've tried to get the access_token and adding it to the script like so.
require 'google/api_client'
require 'google_drive'
client = Google::APIClient.new
access_token = "TokenFromGoogleHardCoded"
$session = GoogleDrive.login_with_oauth(access_token)
# $session doesn't connect
I'm not sure I'm attacking this problem in the correct manor. I would like to save the complete auth variable and hard code it in my scripts.
I figured out this mess.
auth.scope =
"https://www.googleapis.com/auth/drive " +
"https://spreadsheets.google.com/feeds/"
The auth.scope is missing a url. REFERENCE from github
auth.scope =
"https://docs.google.com/feeds/" +
"https://www.googleapis.com/auth/drive " +
"https://spreadsheets.google.com/feeds/"
You can reuse your access_token, but first you need to get it. WARNING: The auth.access_token is only good for an hour. If you need another one you need to call auth.refresh! This will issue you another access_token.
require 'google/api_client'
require 'google_drive'
client = Google::APIClient.new(
:application_name => 'Example Ruby application',
:application_version => '1.0.0'
)
auth = client.authorization
auth.client_id = "YOUR CLIENT ID"
auth.client_secret = "YOUR CLIENT SECRET"
auth.scope =
"https://www.googleapis.com/auth/drive " +
"https://spreadsheets.google.com/feeds/"
auth.redirect_uri = "urn:ietf:wg:oauth:2.0:oob"
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
This chunk of code should print out your access_token/refresh_token in your console. Now you can hard code your application.
require "google/api_client"
require "google_driver"
client = Google::APIClient.new(
:application_name => 'Example Ruby application',
:application_version => '1.0.0'
)
auth = client.authorization
auth.client_id = "Your Client ID"
auth.client_secret = "Your client secret"
access_token = "token you saved from the terminal"
session = GoogleDrive.login_with_oauth(access_token)
for file in session.files
p file.title
end
And eventually your "access_token" will expire. At this point you need to "refresh" it. You can call to see if your access_token is expired by calling
auth.expires_at
You can get a new access token with this example.
require 'google/api_client'
require 'google_drive'
$client_id = "YOUR CLIENT ID"
$client_secret = "YOUR CLIENT SECRET"
$refresh_token = "SAVED REFRESH TOKEN"
client = Google::APIClient.new(:application_name => 'Example Ruby application', :application_version => '1.0.0')
auth = client.authorization
auth.client_id = $client_id
auth.client_secret = $client_secret
auth.scope = "https://docs.google.com/feeds/" + "https://www.googleapis.com/auth/drive " + "https://spreadsheets.google.com/feeds/"
auth.redirect_uri = "urn:ietf:wg:oauth:2.0:oob"
auth.refresh_token = $refresh_token
#here's the magic sauce
auth.refresh!
#as you can see above auth.access_token wasn't passed a value
# but if you call it now you'll see you have a new access_token
auth.access_token
=> new token from server
You might find it easier to use service accounts, as outlined here:
https://github.com/gimite/google-drive-ruby/issues/126#issuecomment-73542381
Although Duck1337's answer will work, you don't actually need to call auth.refresh! with google_drive 1.0.*.
All you need to do is save the refresh_token from when you provided the authorization code in the first instance and then always pass that before calling auth.fetch_access_token! and the tokens will automatically get refreshed.
Below is what I use to login. I use Environment variables rather that code constants, so I can add them to Heroku Config Vars and also to keep sensitive data out of the code.
client = Google::APIClient.new
auth = client.authorization
auth.client_id = ENV['GOOGLE_CLIENT_ID']
auth.client_secret = ENV['GOOGLE_CLIENT_SECRET']
auth.scope = [
"https://www.googleapis.com/auth/drive",
"https://spreadsheets.google.com/feeds/"
]
auth.redirect_uri = "urn:ietf:wg:oauth:2.0:oob"
if ENV['GOOGLE_REFRESH_TOKEN'] == "0" # Always start with 0 in your .env file, e.g. GOOGLE_REFRESH_TOKEN = 0
puts("1. Open this page:\n%s\n\n" % auth.authorization_uri)
puts("2. Enter the authorization code shown in the page: ")
auth.code = $stdin.gets.chomp
end if
auth.refresh_token = ENV['GOOGLE_REFRESH_TOKEN'] #this will be 0 the first time around, but that's OK
auth.fetch_access_token!
if ENV['GOOGLE_REFRESH_TOKEN'] == "0"
puts("3. Save this refresh token:\n%s\n\n" % auth.refresh_token) # you can now replace the 0 in your .env file with this token, so it'll be used permanently. You can also add this to the Heroku Config Vars.
ENV['GOOGLE_REFRESH_TOKEN'] = auth.refresh_token #we'll set it here, so it works without having to alter the .env file for this call
end if
GoogleDrive.login_with_oauth(auth.access_token)
Use capybara and navigate to the token page. Grab it from the page source and save to a variable. Plug the variable when needed. The token string expires so I grab a new one each time I need to access the spreadsheet.
so I'm trying to set up a script to grab tweets so I can use them in my app. Currently I'm using Ruby 2.0.0 and the 1.1 Twitter API REST. Currently I'm not worried about storing the tweets in a database or anything I'm just simply trying to get the correct tweets into terminal. Here is my current code.
require 'twitter'
client = Twitter::REST::Client.new do |config|
config.consumer_key = "XXXXXXXXXXXXXXXXXX"
config.consumer_secret = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
config.access_token = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
config.access_token_secret = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
end
topics = ["#BreakingBad", "#Gameofthones"]
client.filter(:track => topics.join(",")) do |tweet|
puts tweet.text
endtag = options[:search]
My problem is that when I run the script I get flooded with just a mass of tweets in all different languages. Any help would be great. Thanks.
I am very new to ruby and RoR. I would like to save incoming tweets that are currently being displayed on my terminal. Could you explain why the tweets are not being saved?
I run " ruby mine_tweets.rb" in the terminal and the the "puts" of the status.text appears, but there are no entries in the database.
mine_tweets.rb
require 'rubygems'
require 'tweetstream'
puts "searching for turkey....should write to database"
TweetStream.configure do |config|
config.consumer_key = 'XXXXXXX'
config.consumer_secret = 'XXXXXXX'
config.oauth_token = 'XXXXXXX'
config.oauth_token_secret = 'XXXXXXX'
config.auth_method = :oauth
end
# search for "turkey" and will print text and screen name and should store other values in db
TweetStream::Client.new.track('turkey') do |status|
puts status.text + " FROM: #" + status.user.screen_name
Tweet.create(:user_id => status.user.id, :tweet_text => status.text, :screen_name =>status.user.screen_name)
Tweet.save!
end
#client = TweetStream::Client.new
#client.on_delete do |status_id, user_id|
Tweet.delete(status_id)
end
model/tweets.rb
class Tweet < ActiveRecord::Base
attr_accessible :screen_name, :tweet_text, :user_id
end
I recently struggled through this myself. Here is what I found:
In order to save to a database, you need to :
create a database.
connect application to db.
create table and columns
..do something, ie. save, query etc.
close connection (before exiting app)
Here is how i was able to save tweets from the Tweet Stream api into a sqlite local database. (I highly recommend switching directly to Postgres since Heroku doesn't support sqlite).
tweetstream.rb
require 'sqlite3'
require 'tweetstream'
KEY = 'xxx'
SECRET = 'xxx'
TOKEN = 'xxx'
TOKEN_SECRET = 'xxx'
SEARCH_TERMS = "your search terms"
begin
db = SQLite3::Database.open "./db/tweets.db"
db.execute "CREATE TABLE IF NOT EXISTS store_tweets(
id, INTEGER PRIMARY KEY,
tweetid TEXT,
text TEXT,
screen_name TEXT,
userid TEXT,
user_name TEXT,
profile_image_url TEXT,
language,
created_at TEXT,
received_at TIMESTAMPS)"
TweetStream.configure do |config|
config.consumer_key = KEY
config.consumer_secret = SECRET
config.oauth_token = TOKEN
config.oauth_token_secret = TOKEN_SECRET
config.auth_method = :oauth
end
TweetStream::Client.new.track(SEARCH_TERMS) do |status|
puts "#{status.text}"
db.execute( "INSERT INTO store_tweets(
'tweetid',
'text',
'screen_name',
'userid',
'user_name',
'profile_image_url',
'language')
VALUES (?, ?, ?, ?, ?, ?, ?)",
[status[:id]],
[status.text],
[status.user.screen_name],
[status.user[:id]],
[status.user.name],
[status.user.profile_image_url],
[status.lang])
end
rescue SQLite3::Exception => e
puts "Exception occured"
puts e
ensure
db.close if db
end
I'm trying to use Mechanize login to Google Docs so that I can scrape something (not possible from the API) but I keep seem to keep getting a 404 when trying to follow the meta redirect:
require 'rubygems'
require 'mechanize'
USERNAME = "..."
PASSWORD = "..."
LOGIN_URL = "https://www.google.com/accounts/Login?hl=en&continue=http://docs.google.com/"
agent = Mechanize.new
login_page = agent.get(LOGIN_URL)
login_form = login_page.forms.first
login_form.Email = USERNAME
login_form.Passwd = PASSWORD
login_response_page = agent.submit(login_form)
redirect = login_response_page.meta[0].uri.to_s
puts "redirect: #{redirect}"
followed_page = agent.get(redirect) # throws a HTTPNotFound exception
pp followed_page
Can anyone see why this isn't working?
Andy you're awesome!!
Your code helped me to make my script workable and to login into google account. I found your error after couple of hours.It was about html escaping. As I found,Mechanize automatically escapes uri it recieves as a parameter for 'get' method. So my solution is:
EMAIL = ".."
PASSWD = ".."
agent = Mechanize.new{ |a| a.log = Logger.new("mech.log")}
agent.user_agent_alias = 'Linux Mozilla'
agent.open_timeout = 3
agent.read_timeout = 4
agent.keep_alive = true
agent.redirect_ok = true
LOGIN_URL = "https://www.google.com/accounts/Login?hl=en"
login_page = agent.get(LOGIN_URL)
login_form = login_page.forms.first
login_form.Email = EMAIL
login_form.Passwd = PASSWD
login_response_page = agent.submit(login_form)
redirect = login_response_page.meta[0].uri.to_s
puts redirect.split('&')[0..-2].join('&') + "&continue=https://www.google.com/"
followed_page = agent.get(redirect.split('&')[0..-2].join('&') + "&continue=https://www.google.com/adplanner")
pp followed_page
This works just fine for me. I have replaced continue parameter from the meta tag (which is already escaped) by new one.