Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Basic OAuth authorization and identification flow is in and spec'ed.
- Loading branch information
Michael Bleigh
committed
Mar 17, 2009
1 parent
d3ae9b1
commit 689ab05
Showing
14 changed files
with
344 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
module TwitterAuth | ||
class BasicUser < TwitterAuth::GenericUser | ||
|
||
end | ||
end | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
module TwitterAuth | ||
class GenericUser < ActiveRecord::Base | ||
TWITTER_ATTRIBUTES = [ | ||
:name, | ||
:location, | ||
:description, | ||
:profile_image_url, | ||
:url, | ||
:protected, | ||
:profile_background_color, | ||
:profile_sidebar_fill_color, | ||
:profile_link_color, | ||
:profile_sidebar_border_color, | ||
:profile_text_color, | ||
:friends_count, | ||
:statuses_count, | ||
:followers_count, | ||
:favourites_count, | ||
:utc_offset | ||
] | ||
|
||
validates_presence_of :login | ||
validates_format_of :login, :with => /\A[a-z0-9_]+\z/ | ||
validates_length_of :login, :in => 1..15 | ||
validates_uniqueness_of :login | ||
|
||
def self.table_name; 'users' end | ||
|
||
def self.new_from_twitter_hash(hash) | ||
raise ArgumentError, 'Invalid hash: must include screen_name.' unless hash.key?('screen_name') | ||
|
||
user = User.new(:login => hash.delete('screen_name')) | ||
|
||
TWITTER_ATTRIBUTES.each do |att| | ||
user.send("#{att}=", hash[att.to_s]) if user.respond_to?("#{att}=") | ||
end | ||
|
||
user | ||
end | ||
|
||
def assign_twitter_attributes(hash) | ||
TWITTER_ATTRIBUTES.each do |att| | ||
send("#{att}=", hash[att.to_s]) if respond_to?("#{att}=") | ||
end | ||
end | ||
|
||
def update_twitter_attributes(hash) | ||
assign_twitter_attributes(hash) | ||
save | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
module TwitterAuth | ||
class OauthUser < TwitterAuth::GenericUser | ||
def self.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) | ||
|
||
user_info = JSON.parse(token.get('/account/verify_credentials.json').body) | ||
|
||
if user = User.find_by_login(user_info['screen_name']) | ||
user.update_twitter_attributes(user_info) | ||
user | ||
else | ||
User.create_from_twitter_hash_and_token(user_info, token) | ||
end | ||
end | ||
|
||
def self.create_from_twitter_hash_and_token(user_info, access_token) | ||
user = User.new_from_twitter_hash(user_info) | ||
user.access_token = access_token.token | ||
user.access_secret = access_token.secret | ||
user.save | ||
user | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
class TwitterAuth < ActiveRecord::Migration | ||
def self.up | ||
create_table :users do |t| | ||
t.string :login | ||
<% if options[:strategy] == 'basic' %> | ||
t.string :access_token | ||
t.string :access_secret | ||
<% else %> | ||
t.string :crypted_password | ||
t.string :salt | ||
<% end %> | ||
|
||
# This information is automatically kept | ||
# in-sync at each login of the user. You | ||
# may remove any/all of these columns. | ||
t.string :name | ||
t.string :location | ||
t.string :description | ||
t.string :profile_image_url | ||
t.string :url | ||
t.boolean :protected | ||
t.string :profile_background_color | ||
t.string :profile_sidebar_fill_color | ||
t.string :profile_link_color | ||
t.string :profile_sidebar_border_color | ||
t.string :profile_text_color | ||
t.integer :friends_count | ||
t.integer :statuses_count | ||
t.integer :followers_count | ||
t.integer :favourites_count | ||
t.integer :utc_offset | ||
t.string :time_zone # 'Magic field' Rails-compatible time zone pulled from UTC Offset | ||
end | ||
end | ||
|
||
def self.down | ||
drop_table :users | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
# Gem Dependencies | ||
config.gem 'oauth' | ||
|
||
require 'json' | ||
require 'twitter_auth' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
require 'factory_girl' | ||
|
||
Factory.define(:twitter_oauth_user, :class => User) do |u| | ||
u.login 'twitterman' | ||
u.access_token 'fakeaccesstoken' | ||
u.access_secret 'fakeaccesstokensecret' | ||
|
||
u.name 'Twitter Man' | ||
u.description 'Saving the world for all Twitter kind.' | ||
end | ||
|
||
Factory.define(:twitter_basic_user, :class => User) do |u| | ||
u.login 'tweetkid' | ||
u.crypted_password 'fixthislater' | ||
u.salt 'ohsosalty' | ||
|
||
u.name 'Tweet Kid' | ||
u.description 'Twitter Man\'s trusty sidekick.' | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
require 'net/http' | ||
|
||
TWITTER_JSON = { | ||
:verify_credentials => "{\"profile_image_url\":\"http:\\/\\/static.twitter.com\\/images\\/default_profile_normal.png\",\"description\":\"Saving the world for all Twitter kind.\",\"utc_offset\":null,\"favourites_count\":0,\"profile_sidebar_fill_color\":\"e0ff92\",\"screen_name\":\"twitterman\",\"statuses_count\":0,\"profile_background_tile\":false,\"profile_sidebar_border_color\":\"87bc44\",\"friends_count\":2,\"url\":null,\"name\":\"Twitter Man\",\"time_zone\":null,\"protected\":false,\"profile_background_image_url\":\"http:\\/\\/static.twitter.com\\/images\\/themes\\/theme1\\/bg.gif\",\"profile_background_color\":\"9ae4e8\",\"created_at\":\"Fri Feb 06 18:10:32 +0000 2009\",\"profile_text_color\":\"000000\",\"followers_count\":2,\"location\":null,\"id\":20256865,\"profile_link_color\":\"0000ff\"}" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
require File.dirname(__FILE__) + '/../../spec_helper' | ||
|
||
describe TwitterAuth::GenericUser do | ||
should_validate_presence_of :login | ||
should_validate_format_of :login, 'some_guy', 'awesome', 'cool_man' | ||
should_not_validate_format_of :login, 'with-dashes', 'with.periods', 'with spaces' | ||
should_validate_length_of :login, :in => 1..15 | ||
|
||
it 'should validate uniqueness of login' do | ||
Factory.create(:twitter_oauth_user) | ||
Factory.build(:twitter_oauth_user).should have_at_least(1).errors_on(:login) | ||
end | ||
|
||
describe '.new_from_twitter_hash' do | ||
it 'should raise an argument error if the hash does not have a screen_name attribute' do | ||
lambda{User.new_from_twitter_hash({})}.should raise_error(ArgumentError, 'Invalid hash: must include screen_name.') | ||
end | ||
|
||
it 'should return a user' do | ||
User.new_from_twitter_hash({'screen_name' => 'twitterman'}).should be_a(User) | ||
end | ||
|
||
it 'should assign login to the screen_name' do | ||
User.new_from_twitter_hash({'screen_name' => 'twitterman'}).login.should == 'twitterman' | ||
end | ||
|
||
it 'should assign twitter attributes that are provided' do | ||
u = User.new_from_twitter_hash({'screen_name' => 'twitterman', 'name' => 'Twitter Man', 'description' => 'Saving the world for all Tweet kind.'}) | ||
u.name.should == 'Twitter Man' | ||
u.description.should == 'Saving the world for all Tweet kind.' | ||
end | ||
end | ||
|
||
describe '#update_twitter_attributes' do | ||
it 'should assign values to the user' do | ||
user = Factory.create(:twitter_oauth_user, :name => "Dude", :description => "Awesome, man.") | ||
user.update_twitter_attributes({'name' => 'Twitter Man', 'description' => 'Works.'}) | ||
user.reload | ||
user.name.should == 'Twitter Man' | ||
user.description.should == 'Works.' | ||
end | ||
|
||
it 'should not throw an error with extraneous info' do | ||
user = Factory.create(:twitter_oauth_user, :name => "Dude", :description => "Awesome, man.") | ||
lambda{user.update_twitter_attributes({'name' => 'Twitter Man', 'description' => 'Works.', 'whoopsy' => 'noworks.'})}.should_not raise_error | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
require File.dirname(__FILE__) + '/../../spec_helper' | ||
|
||
describe TwitterAuth::OauthUser do | ||
before do | ||
stub_oauth! | ||
end | ||
|
||
describe '.identify_or_create_from_access_token' do | ||
before do | ||
@token = OAuth::AccessToken.new(TwitterAuth.consumer, 'faketoken', 'fakesecret') | ||
end | ||
|
||
it 'should accept an OAuth::AccessToken' do | ||
lambda{ User.identify_or_create_from_access_token(@token) }.should_not raise_error(ArgumentError) | ||
end | ||
|
||
it 'should accept two strings' do | ||
lambda{ User.identify_or_create_from_access_token('faketoken', 'fakesecret') }.should_not raise_error(ArgumentError) | ||
end | ||
|
||
it 'should not accept one string' do | ||
lambda{ User.identify_or_create_from_access_token('faketoken') }.should raise_error(ArgumentError, 'Must authenticate with an OAuth::AccessToken or the string access token and secret.') | ||
end | ||
|
||
it 'should make a call to verify_credentials' do | ||
# this is in the before, just making it explicit | ||
User.identify_or_create_from_access_token(@token) | ||
end | ||
|
||
it 'should try to find the user with that login' do | ||
User.should_receive(:find_by_login).once.with('twitterman') | ||
User.identify_or_create_from_access_token(@token) | ||
end | ||
|
||
it 'should return the user if he/she exists' do | ||
user = Factory.create(:twitter_oauth_user, :login => 'twitterman') | ||
User.identify_or_create_from_access_token(@token).should == user | ||
end | ||
|
||
it 'should update the user\'s attributes based on the twitter info' do | ||
user = Factory.create(:twitter_oauth_user, :login => 'twitterman', :name => 'Not Twitter Man') | ||
User.identify_or_create_from_access_token(@token).name.should == 'Twitter Man' | ||
end | ||
|
||
it 'should create a user if one does not exist' do | ||
lambda{User.identify_or_create_from_access_token(@token)}.should change(User, :count).by(1) | ||
end | ||
|
||
it 'should assign the oauth access token and secret' do | ||
user = User.identify_or_create_from_access_token(@token) | ||
user.access_token.should == @token.token | ||
user.access_secret.should == @token.secret | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
ActiveRecord::Schema.define :version => 0 do | ||
create_table :twitter_auth_users, :force => true do |t| | ||
t.string :login | ||
|
||
# OAuth fields | ||
t.string :access_token | ||
t.string :access_secret | ||
|
||
# Basic fields | ||
t.string :crypted_password | ||
t.string :salt | ||
|
||
# This information is automatically kept | ||
# in-sync at each login of the user. You | ||
# may remove any/all of these columns. | ||
t.string :name | ||
t.string :location | ||
t.string :description | ||
t.string :profile_image_url | ||
t.string :url | ||
t.boolean :protected | ||
t.string :profile_background_color | ||
t.string :profile_sidebar_fill_color | ||
t.string :profile_link_color | ||
t.string :profile_sidebar_border_color | ||
t.string :profile_text_color | ||
t.integer :friends_count | ||
t.integer :statuses_count | ||
t.integer :followers_count | ||
t.integer :favourites_count | ||
t.integer :utc_offset | ||
t.string :time_zone # 'Magic field' Rails-compatible time zone pulled from UTC Offset | ||
end | ||
|
||
end | ||
|
Oops, something went wrong.