Permalink
Browse files

green features

  • Loading branch information...
1 parent db70648 commit 2041d10473c1078014e198fcf14b0a54e0ccb920 @jasonm jasonm committed Mar 14, 2010
@@ -4,10 +4,63 @@ def new
@request_token = ClearanceTwitter.consumer.get_request_token({:oauth_callback=>oauth_callback})
session[:request_token] = @request_token.token
session[:request_token_secret] = @request_token.secret
-
+
url = @request_token.authorize_url
# TODO: Test for this
# url << "&oauth_callback=#{CGI.escape(ClearanceTwitter.oauth_callback)}" if ClearanceTwitter.oauth_callback?
redirect_to url
end
+
+ def oauth_callback
+ puts "Doing the #oauth_callback"
+ puts "---Session---"
+ p session
+ puts "---Params---"
+ p params
+ unless session[:request_token] && session[:request_token_secret]
+ deny_access('No authentication information was found in the session. Please try again.') and return
+ end
+
+ unless params[:oauth_token].blank? || session[:request_token] == params[:oauth_token]
+ deny_access('Authentication information does not match session information. Please try again.') and return
+ end
+
+ @request_token = OAuth::RequestToken.new(ClearanceTwitter.consumer, session[:request_token], session[:request_token_secret])
+
+ oauth_verifier = params["oauth_verifier"]
+ @access_token = @request_token.get_access_token(:oauth_verifier => oauth_verifier)
+
+ # The request token has been invalidated
+ # so we nullify it in the session.
+ session[:request_token] = nil
+ session[:request_token_secret] = nil
+
+ @user = User.identify_or_create_from_access_token(@access_token)
+
+ sign_in(@user)
+
+ # TODO: What to do here?
+ # cookies[:remember_token] = @user.remember_me
+
+ flash_success_after_callback
+ redirect_to url_after_callback
+ rescue Net::HTTPServerException => e
+ case e.message
+ when '401 "Unauthorized"'
+ deny_access('This authentication request is no longer valid. Please try again.') and return
+ else
+ deny_access('There was a problem trying to authenticate you. Please try again.') and return
+ end
+ end
+
+ private
+
+ def url_after_callback
+ root_url
+ end
+
+ def flash_success_after_callback
+ flash[:success] = "Successfully signed in with Twitter."
+ end
+
end
@@ -0,0 +1,157 @@
+module ClearanceTwitter
+ module Dispatcher
+ module Shared
+ # def post!(status)
+ # self.post('/statuses/update.json', :status => status)
+ # end
+
+ # def append_extension_to(path)
+ # path, query_string = *(path.split("?"))
+ # path << '.json' unless path.match(/\.(:?xml|json)\z/i)
+ # "#{path}#{"?#{query_string}" if query_string}"
+ # end
+
+ def handle_response(response)
+ case response
+ when Net::HTTPOK
+ begin
+ JSON.parse(response.body)
+ rescue JSON::ParserError
+ response.body
+ end
+ when Net::HTTPUnauthorized
+ raise TwitterAuth::Dispatcher::Unauthorized, 'The credentials provided did not authorize the user.'
+ else
+ message = begin
+ JSON.parse(response.body)['error']
+ rescue JSON::ParserError
+ if match = response.body.match(/<error>(.*)<\/error>/)
+ match[1]
+ else
+ 'An error occurred processing your Twitter request.'
+ end
+ end
+
+ raise TwitterAuth::Dispatcher::Error, message
+ end
+ end
+ end
+ end
+
+ module LinkedUser
+ TWITTER_ATTRIBUTES = [
+ :name
+ ]
+
+ def self.included(model)
+ # TODO Unit test the following
+ # base.class_eval do
+ # attr_protected :access_token, :access_secret
+ # end
+
+ model.class_eval do
+ extend ClearanceTwitter::LinkedUser::ClassMethods
+ extend ClearanceTwitter::Dispatcher::Shared
+ include InstanceMethods
+ end
+ end
+
+ module InstanceMethods
+ def email_optional?
+ super || twitter_user?
+ end
+
+ def password_optional?
+ super || twitter_user?
+ end
+
+ def twitter_user?
+ twitter_access_token.present?
+ end
+
+ def assign_twitter_attributes(hash)
+ TWITTER_ATTRIBUTES.each do |att|
+ send("#{att}=", hash[att.to_s]) if respond_to?("#{att}=")
+ end
+ end
+
+ # def facebook_user
+ # if facebook_user?
+ # Facebooker::User.new(fb_user_id)
+ # else
+ # nil
+ # end
+ # end
+
+ # def linked_on_facebook_to?(facebook_user)
+ # facebook_user.uid == fb_user_id
+ # end
+
+ # def link_on_facebook_to(facebook_user)
+ # self.fb_user_id = facebook_user.uid
+ # save
+ # end
+ end
+
+ module ClassMethods
+ def identify_or_create_from_access_token(token, secret=nil)
+ # raise ArgumentError, 'Must authenticate with an OAuth::AccessToken or the string access token and secret.' unless (token && secret) || token.is_a?(OAuth::AccessToken)
+
+ token = OAuth::AccessToken.new(ClearanceTwitter.consumer, token, secret) unless token.is_a?(OAuth::AccessToken)
+
+ response = token.get(ClearanceTwitter.path_prefix + '/account/verify_credentials.json')
+ user_info = handle_response(response)
+
+ puts "*"*80
+ puts "user_info:"
+ p user_info
+
+ if user = User.find_by_twitter_username(user_info['screen_name'].to_s)
+ puts "found existing user with twitter_username"
+ user.twitter_username = user_info['screen_name']
+ user.assign_twitter_attributes(user_info)
+ user.twitter_access_token = token.token
+ user.twitter_access_secret = token.secret
+ raise "Inside #identify_or_create_from_access_token, trying to save invalid user:\n#{user.errors.full_messages}" if !user.valid?
+ user.save
+
+ puts "*"*80
+ puts "the new User:"
+ p user
+
+ user
+ else
+ puts "found existing user with twitter_username"
+ User.create_from_twitter_hash_and_token(user_info, token)
+ end
+ end
+
+ def create_from_twitter_hash_and_token(user_info, access_token)
+ user = User.new_from_twitter_hash(user_info)
+ user.twitter_access_token = access_token.token
+ user.twitter_access_secret = access_token.secret
+ raise "Inside #create_from_twitter_hash_and_token, trying to save invalid user:\n#{user.errors.full_messages}" if !user.valid?
+ user.save
+ user
+ end
+
+ def new_from_twitter_hash(hash)
+ # raise ArgumentError, 'Invalid hash: must include screen_name.' unless hash.key?('screen_name')
+ # raise ArgumentError, 'Invalid hash: must include id.' unless hash.key?('id')
+
+ user = User.new
+ # TODO Add test to motivate #twitter_id
+ # user.twitter_id = hash['id'].to_s
+ user.twitter_username = hash['screen_name']
+ user.assign_twitter_attributes(hash)
+
+ user
+ end
+ end
+
+ # def token
+ # OAuth::AccessToken.new(TwitterAuth.consumer, access_token, access_secret)
+ # end
+ end
+end
+
@@ -15,8 +15,9 @@ def manifest
# :after => 'include Clearance::Authentication'
m.insert_into 'config/routes.rb', 'ClearanceTwitter::Routes.draw(map)'
m.file 'sign_in_with_twitter.png', 'public/images/sign_in_with_twitter.png'
-# m.insert_into 'app/models/user.rb', "include ClearanceTwitter::LinkedUser",
-# :after => /include Clearance::User\s*$/
+ m.file 'twitter_auth.yml', 'config/twitter_auth.yml'
+ m.insert_into 'app/models/user.rb', "include ClearanceTwitter::LinkedUser",
+ :after => /include Clearance::User\s*$/
# m.readme "README"
end
end
@@ -2,13 +2,13 @@ class AddClearanceTwitterFieldsToUsers < ActiveRecord::Migration
def self.up
add_column :users, :twitter_username, :string
add_column :users, :twitter_id, :string
- add_column :users, :access_token, :string
- add_column :users, :access_secret, :string
+ add_column :users, :twitter_access_token, :string
+ add_column :users, :twitter_access_secret, :string
end
def self.down
- remove_column :users, :access_token
- remove_column :users, :access_secret
+ remove_column :users, :twitter_access_token
+ remove_column :users, :twitter_access_secret
remove_column :users, :twitter_id
remove_column :users, :twitter_username
end
@@ -0,0 +1,31 @@
+development:
+ oauth_consumer_key: add_your_consumer_key_here
+ oauth_consumer_secret: add_your_consumer_secret_here
+ base_url: "https://twitter.com"
+
+ # Use /oauth/authorize for traditional OAuth
+ # Use /oauth/authenticate for the more streamlined "Sign in with Twitter"
+ # Learn more at: http://apiwiki.twitter.com/Sign-in-with-Twitter
+ authorize_path: "/oauth/authenticate"
+
+ # api_timeout: 10
+ # remember_for: 14 # days
+ oauth_callback: "http://localhost:3000/oauth_callback_twitter_users"
+test:
+ strategy: oauth
+ oauth_consumer_key: testkey
+ oauth_consumer_secret: testsecret
+ base_url: "https://twitter.com"
+ authorize_path: "/oauth/authenticate"
+ # api_timeout: 10
+ # remember_for: 14 # days
+ oauth_callback: "http://localhost:3000/oauth_callback_twitter_users"
+cucumber:
+ strategy: oauth
+ oauth_consumer_key: testkey
+ oauth_consumer_secret: testsecret
+ base_url: "https://twitter.com"
+ authorize_path: "/oauth/authenticate"
+ # api_timeout: 10
+ # remember_for: 14 # days
+ oauth_callback: "http://localhost:3000/oauth_callback_twitter_users"
@@ -21,12 +21,24 @@
end
Then 'I should be signed in as Twitter user "$username"' do |twitter_username|
- assert user = User.find_by_twitter_username(twitter_username), "No user exists for Twitter username #{twitter_username.inspect}"
+ assert user = User.find_by_twitter_username(twitter_username), "No user exists for Twitter username #{twitter_username.inspect}. Users:\n#{User.all.inspect}"
assert_equal user, @controller.current_user, "Not signed in as the correct Twitter user"
end
When 'I grant access to the Twitter application for Twitter user "$twitter_username"' do |twitter_username|
- pending # express the regexp above with the code you wish you had
+ # user = stub('user', :id => '1', :remember_me => '2', :login => 'boys', :geocoded_location => FakeGeocoder.geocode() )
+ # request_token = stub('request_token', :get_access_token => 'access_token')
+ # User.stubs(:identify_or_create_from_access_token).returns(user)
+ # CrushesController.any_instance.stubs(:current_user).returns(user)
+ # OAuth::RequestToken.stubs(:new).returns(request_token)
+ #
+# {:session_id=>"4f7fe62bf1ed8509899b954469b12e16", :request_token_secret=>"same_for_this", :request_token=>"this_need_not_be_real"}
+# ---Params---
+# {"action"=>"oauth_callback", "oauth_verifier"=>"verifier", "oauth_token"=>"token", "controller"=>"clearance_twitter/twitter_users"}
+# And I grant access to the Twitter application for Twitter user "jerk
+
+ FakeTwitter.stub_verify_credentials_for(twitter_username)
+ visit oauth_callback_twitter_users_url(:oauth_token => 'this_need_not_be_real', :oauth_verifier => 'verifier')
end
When 'I deny access to the Twitter application' do
@@ -61,13 +73,4 @@
# Then /^I should be directed to Twitter OAuth$/ do
# assert_redirected_to(TwitterAuth.config['base_url'] + TwitterAuth.config['authorize_path'] + '&oauth_callback=' + CGI.escape(TwitterAuth.config['oauth_callback']))
# end
-#
-# When /^I return from Twitter OAuth with a valid OAuth verifier for "@([^\"]*)"$/ do |username|
-# user = stub('user', :id => '1', :remember_me => '2', :login => 'boys', :geocoded_location => FakeGeocoder.geocode() )
-# request_token = stub('request_token', :get_access_token => 'access_token')
-# User.stubs(:identify_or_create_from_access_token).returns(user)
-# CrushesController.any_instance.stubs(:current_user).returns(user)
-# OAuth::RequestToken.stubs(:new).returns(request_token)
-# visit oauth_callback_url(:oauth_token => 'token', :oauth_verifier => 'verifier')
-# end
@@ -10,5 +10,8 @@ Feature: Sign in with Twitter OAuth
When I go to the sign in page
And I click the Sign in with Twitter button
And I grant access to the Twitter application for Twitter user "jerkcity"
- Then I should be signed in as Twitter user "jerkcity"
+ Then I should see "Successfully signed in with Twitter."
And there should be 1 user in the system
+ And I should be signed in as Twitter user "jerkcity"
+
+ Scenario: Signed in user connects their Twitter account
@@ -3,15 +3,15 @@ Feature: Sign up with Twitter OAuth
A visitor to the site
Should be able to sign up with Twitter OAuth
- @wip
Scenario: User successfully signs up with Twitter OAuth
Given there are no users
And Twitter OAuth is faked
And I go to the sign up page
And I click the Sign in with Twitter button
And I grant access to the Twitter application for Twitter user "jerkcity"
- Then I should be signed in as Twitter user "jerkcity"
+ Then I should see "Successfully signed in with Twitter."
And there should be 1 user in the system
+ And I should be signed in as Twitter user "jerkcity"
# Deny access
# http://beerfire.heroku.com/oauth_callback?denied=gDvIISsUyVIKEsMZSmMCWPUOy3VwMU5xcRfc52GzMqk
Oops, something went wrong.

0 comments on commit 2041d10

Please sign in to comment.