diff --git a/app/controllers/settings_controller.rb b/app/controllers/settings_controller.rb index fa0c967..a597080 100644 --- a/app/controllers/settings_controller.rb +++ b/app/controllers/settings_controller.rb @@ -171,7 +171,7 @@ class SettingsController < ApplicationController def github_callback if !session[:github_state].present? || !params[:code].present? || (params[:state].to_s != session[:github_state].to_s) - flash[:error] = "No OAuth state" + flash[:error] = "Invalid OAuth state" return redirect_to "/settings" end @@ -199,6 +199,45 @@ class SettingsController < ApplicationController return redirect_to "/settings" end + def twitter_auth + session[:twitter_state] = SecureRandom.hex + return redirect_to Twitter.oauth_auth_url(session[:twitter_state]) + end + + def twitter_callback + if !session[:twitter_state].present? || + (params[:state].to_s != session[:twitter_state].to_s) + flash[:error] = "Invalid OAuth state" + return redirect_to "/settings" + end + + session.delete(:twitter_state) + + tok, sec, username = Twitter.token_secret_and_user_from_token_and_verifier( + params[:oauth_token], params[:oauth_verifier]) + if tok.present? && username.present? + @user.twitter_oauth_token = tok + @user.twitter_oauth_token_secret = sec + @user.twitter_username = username + @user.save! + flash[:success] = "Your account has been linked to Twitter user @" << + "#{username}." + else + return twitter_disconnect + end + + return redirect_to "/settings" + end + + def twitter_disconnect + @user.twitter_oauth_token = nil + @user.twitter_username = nil + @user.twitter_oauth_token_secret = nil + @user.save! + flash[:success] = "Your Twitter association has been removed." + return redirect_to "/settings" + end + private def user_params diff --git a/app/models/user.rb b/app/models/user.rb index 9be77e0..5e32b1d 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -48,6 +48,9 @@ class User < ActiveRecord::Base s.string :totp_secret s.string :github_oauth_token s.string :github_username + s.string :twitter_oauth_token + s.string :twitter_oauth_token_secret + s.string :twitter_username end validates :email, :format => { :with => /\A[^@ ]+@[^@ ]+\.[^@ ]+\Z/ }, @@ -121,6 +124,10 @@ class User < ActiveRecord::Base h[:github_username] = self.github_username end + if self.twitter_username.present? + h[:twitter_username] = self.twitter_username + end + h end diff --git a/app/views/settings/index.html.erb b/app/views/settings/index.html.erb index b6c55ee..9618683 100644 --- a/app/views/settings/index.html.erb +++ b/app/views/settings/index.html.erb @@ -246,6 +246,21 @@ <% end %> + <% if Twitter.enabled? %> +
+ <%= label_tag :twitter_username, "Twitter:", :class => "required" %> + <% if @edit_user.twitter_username.present? %> + Linked to + @<%= h(@edit_user.twitter_username) %> + (<%= link_to "Disconnect", "/settings/twitter_disconnect", + :method => :post %>) + <% else %> + Connect + <% end %> +
+ <% end %> +

diff --git a/config/routes.rb b/config/routes.rb index 6135757..4f8bda7 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -121,6 +121,9 @@ Lobsters::Application.routes.draw do get "/settings/github_auth" => "settings#github_auth" get "/settings/github_callback" => "settings#github_callback" post "/settings/github_disconnect" => "settings#github_disconnect" + get "/settings/twitter_auth" => "settings#twitter_auth" + get "/settings/twitter_callback" => "settings#twitter_callback" + post "/settings/twitter_disconnect" => "settings#twitter_disconnect" get "/filters" => "filters#index" post "/filters" => "filters#update" diff --git a/extras/twitter.rb b/extras/twitter.rb index 6a7f5db..8650b07 100644 --- a/extras/twitter.rb +++ b/extras/twitter.rb @@ -4,6 +4,9 @@ class Twitter # these need to be overridden in config/initializers/production.rb @@CONSUMER_KEY = nil @@CONSUMER_SECRET = nil + + # these are set for the account used to post updates in + # script/post_to_twitter (needs read/write access) @@AUTH_TOKEN = nil @@AUTH_SECRET = nil @@ -12,6 +15,10 @@ class Twitter # https://t.co/eyW1U2HLtP TCO_LEN = 23 + def self.enabled? + self.CONSUMER_KEY.present? + end + def self.oauth_consumer OAuth::Consumer.new(self.CONSUMER_KEY, self.CONSUMER_SECRET, { :site => "https://api.twitter.com" }) @@ -47,4 +54,28 @@ class Twitter end end end + + def self.token_secret_and_user_from_token_and_verifier(tok, verifier) + rt = OAuth::RequestToken.from_hash(self.oauth_consumer, + { :oauth_token => tok }) + at = rt.get_access_token({ :oauth_verifier => verifier }) + + res = at.get("/1.1/account/verify_credentials.json") + js = JSON.parse(res.body) + + if !js["screen_name"].present? + return nil + end + + [ at.token, at.secret, js["screen_name"] ] + end + + def self.oauth_request_token(state) + self.oauth_consumer.get_request_token(:oauth_callback => + Rails.application.root_url + "settings/twitter_callback?state=#{state}") + end + + def self.oauth_auth_url(state) + self.oauth_request_token(state).authorize_url + end end