Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

fixed everything up

  • Loading branch information...
commit 1d437509e02b1704fa94e997f870dcf9973a1801 1 parent ffd3fa5
Nick Howard authored
32 Rakefile
@@ -5,12 +5,12 @@ begin
5 5 require 'jeweler'
6 6 Jeweler::Tasks.new do |gem|
7 7 gem.name = "sinatra-twitter-oauth"
8   - gem.summary = %Q{TODO: one-line summary of your gem}
  8 + gem.summary = %Q{A Sinatra Extension that simplifies using twitter for login and authentication.}
9 9 gem.description = %Q{TODO: longer description of your gem}
10 10 gem.email = "ndh@baroquebobcat.com"
11 11 gem.homepage = "http://github.com/baroquebobcat/sinatra-twitter-oauth"
12 12 gem.authors = ["Nick Howard"]
13   - gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
  13 + gem.add_development_dependency "rspec", ">= 1.2.9"
14 14 # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
15 15 end
16 16 Jeweler::GemcutterTasks.new
@@ -18,29 +18,21 @@ rescue LoadError
18 18 puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
19 19 end
20 20
21   -require 'rake/testtask'
22   -Rake::TestTask.new(:test) do |test|
23   - test.libs << 'lib' << 'test'
24   - test.pattern = 'test/**/test_*.rb'
25   - test.verbose = true
  21 +require 'spec/rake/spectask'
  22 +Spec::Rake::SpecTask.new(:spec) do |spec|
  23 + spec.libs << 'lib' << 'spec'
  24 + spec.spec_files = FileList['spec/**/*_spec.rb']
26 25 end
27 26
28   -begin
29   - require 'rcov/rcovtask'
30   - Rcov::RcovTask.new do |test|
31   - test.libs << 'test'
32   - test.pattern = 'test/**/test_*.rb'
33   - test.verbose = true
34   - end
35   -rescue LoadError
36   - task :rcov do
37   - abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
38   - end
  27 +Spec::Rake::SpecTask.new(:rcov) do |spec|
  28 + spec.libs << 'lib' << 'spec'
  29 + spec.pattern = 'spec/**/*_spec.rb'
  30 + spec.rcov = true
39 31 end
40 32
41   -task :test => :check_dependencies
  33 +task :spec => :check_dependencies
42 34
43   -task :default => :test
  35 +task :default => :spec
44 36
45 37 require 'rake/rdoctask'
46 38 Rake::RDocTask.new do |rdoc|
70 lib/sinatra-twitter-oauth.rb
... ... @@ -0,0 +1,70 @@
  1 +require 'sinatra/base'
  2 +require 'twitter_oauth'
  3 +
  4 +require 'sinatra-twitter-oauth/twitter_oauth_ext'
  5 +require 'sinatra-twitter-oauth/helpers'
  6 +#Sinatra::TwitterOAuth
  7 +#
  8 +# A sinatra extension that abstracts away most of
  9 +# using twitter oauth for login
  10 +#
  11 +#twitter_oauth_config
  12 +#options
  13 +# key -- oauth consumer key
  14 +# secret -- oauth consumer secret
  15 +# callback -- oauth callback url. Must be absolute. e.g. http://example.com/auth
  16 +# login_template -- a single entry hash with the engine as the key e.g. :login_template => {:haml => :login}
  17 +module Sinatra
  18 + module TwitterOAuth
  19 +
  20 + DEFAULT_CONFIG = {
  21 + :key => 'changeme',
  22 + :secret => 'changeme',
  23 + :callback => 'changeme',
  24 + :login_template => {:text=>'<a href="/connect">Login using Twitter</a>'}
  25 + }
  26 +
  27 + def self.registered app
  28 +
  29 + app.helpers Helpers
  30 + app.enable :sessions
  31 + app.set :twitter_oauth_config, DEFAULT_CONFIG
  32 +
  33 + app.get '/login' do
  34 + redirect '/' if @user
  35 +
  36 + login_config = options.twitter_oauth_config[:login_template]
  37 +
  38 + engine = login_config.keys.first
  39 +
  40 + case engine
  41 + when :text
  42 + login_config[:text]
  43 + else
  44 + render engine, login_config[engine]
  45 + end
  46 + end
  47 +
  48 + app.get '/connect' do
  49 + redirect_to_twitter_auth_url
  50 + end
  51 +
  52 + app.get '/auth' do
  53 + if authenticate!
  54 + redirect '/'
  55 + else
  56 + status 403
  57 + 'Not Authenticated'
  58 + end
  59 + end
  60 +
  61 + app.get '/logout' do
  62 + clear_oauth_session
  63 + redirect '/login'
  64 + end
  65 + end
  66 +
  67 + end
  68 +
  69 + register TwitterOAuth
  70 +end
78 lib/sinatra-twitter-oauth/helpers.rb
... ... @@ -0,0 +1,78 @@
  1 +module Sinatra::TwitterOAuth
  2 + module Helpers
  3 +
  4 + def login_required
  5 + setup_client
  6 +
  7 + @user = ::TwitterOAuth::User.new(@client, session[:user]) if session[:user]
  8 +
  9 + @rate_limit_status = @client.rate_limit_status
  10 +
  11 + redirect '/login' unless @user
  12 + end
  13 +
  14 + def setup_client
  15 + @client ||= ::TwitterOAuth::Client.new(
  16 + :consumer_secret => options.twitter_oauth_config[:secret],
  17 + :consumer_key => options.twitter_oauth_config[:key],
  18 + :token => session[:access_token],
  19 + :secret => session[:secret_token]
  20 + )
  21 + end
  22 +
  23 + def get_request_token
  24 + setup_client
  25 +
  26 + begin
  27 + @client.authentication_request_token(:oauth_callback=>options.twitter_oauth_config[:callback])
  28 + rescue StandardError => e
  29 + halt 500,'check your key & secret'
  30 + end
  31 + end
  32 +
  33 + def get_access_token
  34 + setup_client
  35 +
  36 + begin
  37 + @client.authorize(
  38 + session[:request_token],
  39 + session[:request_token_secret],
  40 + :oauth_verifier => params[:oauth_verifier]
  41 + )
  42 + rescue OAuth::Unauthorized => e
  43 + nil
  44 + end
  45 + end
  46 +
  47 + def redirect_to_twitter_auth_url
  48 + request_token = get_request_token
  49 +
  50 + session[:request_token] = request_token.token
  51 + session[:request_token_secret]= request_token.secret
  52 +
  53 + redirect request_token.authorize_url.gsub('authorize','authenticate')
  54 + end
  55 +
  56 + def authenticate!
  57 + access_token = get_access_token
  58 +
  59 + if @client.authorized?
  60 + session[:access_token] = access_token.token
  61 + session[:secret_token] = access_token.secret
  62 + session[:user] = @client.info
  63 +
  64 + session[:user]
  65 + else
  66 + nil
  67 + end
  68 + end
  69 +
  70 + def clear_oauth_session
  71 + session[:user] = nil
  72 + session[:request_token] = nil
  73 + session[:request_token_secret] = nil
  74 + session[:access_token] = nil
  75 + session[:secret_token] = nil
  76 + end
  77 + end
  78 +end
79 lib/sinatra-twitter-oauth/twitter_oauth_ext.rb
... ... @@ -0,0 +1,79 @@
  1 +
  2 +#
  3 +# Some additional domain model classes for twitter oauth.
  4 +#
  5 +module TwitterOAuth
  6 +
  7 + class User
  8 + attr_accessor :client,:info
  9 +
  10 + def initialize client,info
  11 + self.client = client
  12 + self.info = info
  13 + end
  14 +
  15 + def lists
  16 + client.get_lists(screen_name)['lists'].map {|list| List.new client, list}
  17 + end
  18 +
  19 + def list list_name
  20 + List.new client, client.get_list(screen_name, list_name)
  21 + end
  22 +
  23 + def new_list list_name,options={}
  24 + List.new client, client.create_list(screen_name, list_name, options)
  25 + end
  26 +
  27 + def destroy_list list_name
  28 + client.delete_list screen_name, list_name
  29 + end
  30 +
  31 + def method_missing method, *args
  32 + info[method.to_s]
  33 + end
  34 + end
  35 +
  36 +
  37 + class List
  38 +
  39 + attr_accessor :client,:info
  40 +
  41 + #params:
  42 + # client: instance of TwitterOAuth::Client
  43 + # info: the result of client.get_list
  44 + def initialize client,info
  45 + self.info = info
  46 + self.client = client
  47 + end
  48 +
  49 + def add_member screen_name
  50 + client.add_member_to_list user['screen_name'],slug, client.show(screen_name)["id"]
  51 + end
  52 +
  53 + def add_members screen_names
  54 + screen_names.each {|name| add_member name }
  55 + end
  56 +
  57 + def remove_member screen_name
  58 + client.remove_member_from_list user['screen_name'],slug, client.show(screen_name)["id"]
  59 + end
  60 +
  61 + def remove_members screen_names
  62 + screen_names.each {|name| remove_member name }
  63 + end
  64 +
  65 + def members
  66 + client.list_members(user['screen_name'], slug)['users'].map{|user| User.new(client,user)}
  67 + end
  68 +
  69 + def private?
  70 + mode == 'private'
  71 + end
  72 +
  73 + def method_missing method, *args
  74 + info[method.to_s]
  75 + end
  76 +
  77 + end
  78 +end
  79 +
99 spec/sinatra-twitter-oauth_spec.rb
... ... @@ -0,0 +1,99 @@
  1 +require 'spec_helper'
  2 +
  3 +class TestApp < Sinatra::Base
  4 + register Sinatra::TwitterOAuth
  5 +
  6 + get '/' do
  7 + login_required
  8 + 'hello world'
  9 + end
  10 +end
  11 +
  12 +describe Sinatra::TwitterOAuth do
  13 +
  14 + def app
  15 + TestApp
  16 + end
  17 +
  18 + before do
  19 + @client=mock('client',
  20 + :rate_limit_status=>{
  21 + "remaining_hits"=>150,
  22 + "hourly_limit"=>150,
  23 + "reset_time_in_seconds"=>0,
  24 + "reset_time"=>"Sat Jan 01 00:00:00 UTC 2000"
  25 + })
  26 + TwitterOAuth::Client.stub!(:new).and_return(
  27 + @client=mock('client',
  28 + :rate_limit_status=>{"remaining_hits"=>150,"hourly_limit"=>150,"reset_time_in_seconds"=>0,"reset_time"=>"Sat Jan 01 00:00:00 UTC 2000"}))
  29 +
  30 + TwitterOAuth::User.stub!(:new).and_return(@user = mock('user'))
  31 +
  32 + @authed_session = {'rack.session'=>{:user => {'screen_name'=>'tester'}}}
  33 + end
  34 +
  35 + describe 'protected by login_required' do
  36 + it 'redirects to /login when unauthenticated' do
  37 + get '/'
  38 + last_response.should be_redirect
  39 + last_response.location.should == '/login'
  40 + end
  41 +
  42 + it 'lets you through if you are authed' do
  43 + @user.stub!(:lists).and_return [mock('list',:null_object=>true)]
  44 + get '/',{},@authed_session
  45 + last_response.location.should be_nil
  46 + last_response.should be_ok
  47 + end
  48 + end
  49 +
  50 + describe 'GET /login' do
  51 + it 'is never redirected' do
  52 + get '/login'
  53 + last_response.location.should be_nil
  54 + last_response.should be_ok
  55 + end
  56 + end
  57 +
  58 +
  59 + describe 'GET /connect' do
  60 + it 'gets a request token' do
  61 + @client.should_receive(:authentication_request_token).and_return(mock('request token',:authorize_url=>'http://example.com',:token=>'token',:secret=>'secret'))
  62 + get '/connect'
  63 + end
  64 + it "redirects to the request token's auth url" do
  65 + @client.stub!(:authentication_request_token).and_return(token = mock('request token',:token=>'token',:secret=>'secret'))
  66 + token.should_receive(:authorize_url).and_return 'http://example.com'
  67 + get '/connect'
  68 + last_response.location.should == 'http://example.com'
  69 + end
  70 + end
  71 +
  72 + describe 'GET /auth' do
  73 + describe "on auth denied" do
  74 + it "responds with 'Not Authenticated' and a 403" do
  75 + @client.stub!(:authorize).and_raise OAuth::Unauthorized.new
  76 + @client.stub!(:authorized?).and_return false
  77 + get '/auth'
  78 + last_response.status.should == 403
  79 + last_response.body.should == 'Not Authenticated'
  80 + end
  81 + end
  82 + describe 'on auth success' do
  83 + it "redirects to '/'" do
  84 + @client.stub!(:authorize).and_return(mock('access token',:null_object => true))
  85 + @client.stub!(:authorized?).and_return true
  86 + @client.stub!(:info).and_return(mock(:user))
  87 + get '/auth'
  88 + last_response.location.should == '/'
  89 + end
  90 + end
  91 + end
  92 +
  93 + describe "GET /logout" do
  94 + it "redirects to /login" do
  95 + get '/logout',{},@authed_session
  96 + last_response.location.should == '/login'
  97 + end
  98 + end
  99 +end
10 spec/spec_helper.rb
... ... @@ -0,0 +1,10 @@
  1 +ENV['RACK_ENV'] = 'test'
  2 +require 'rubygems'
  3 +
  4 +require File.expand_path('../lib/sinatra-twitter-oauth', File.dirname(__FILE__))
  5 +
  6 +require 'spec'
  7 +require 'spec/interop/test'
  8 +require 'rack/test'
  9 +
  10 +Test::Unit::TestCase.send :include, Rack::Test::Methods
10 test/helper.rb
... ... @@ -1,10 +0,0 @@
1   -require 'rubygems'
2   -require 'test/unit'
3   -require 'shoulda'
4   -
5   -$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6   -$LOAD_PATH.unshift(File.dirname(__FILE__))
7   -require 'sinatra-twitter-oauth'
8   -
9   -class Test::Unit::TestCase
10   -end
7 test/test_sinatra-twitter-oauth.rb
... ... @@ -1,7 +0,0 @@
1   -require 'helper'
2   -
3   -class TestSinatraTwitterOauth < Test::Unit::TestCase
4   - should "probably rename this file and start testing for real" do
5   - flunk "hey buddy, you should probably rename this file and start testing for real"
6   - end
7   -end

0 comments on commit 1d43750

Please sign in to comment.
Something went wrong with that request. Please try again.