rest-graph 1.2.1 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES CHANGED
@@ -1,5 +1,27 @@
1
1
  = rest-graph changes history
2
2
 
3
+ == rest-graph 1.3.0 -- 2010-06-11
4
+ * Now rest-graph is rescuing all exceptions from rest-client.
5
+ * Added RestGraph#exchange_sessions to exchange old sessions to access tokens.
6
+
7
+ * Added RestGraph#old_rest, see:
8
+ http://developers.facebook.com/docs/reference/rest/
9
+
10
+ * Now all API request accept an additional options argument,
11
+ you may pass :suppress_decode => true to turn off auto-decode this time.
12
+ e.g. rg.get('bad/json', {:query => 'string'}, :suppress_decode => true)
13
+ This is for Facebook who didn't always return JSON in response.
14
+
15
+ * Renamed fql_server to old_server.
16
+ * Favor yaji/json_gem first, then falls back to json, and json_pure.
17
+ * Fixed a bug that cookie format from Facebook varies. No idea why.
18
+
19
+ for RailsUtil:
20
+
21
+ * Big and fat refactoring in RailsUtil, see example for detail:
22
+ http://github.com/cardinalblue/rest-graph/tree/rest-graph-1.3.0/example
23
+ * url_for and link_to would auto pass :host option if it's inside canvas.
24
+
3
25
  == rest-graph 1.2.1 -- 2010-06-02
4
26
  * Deprecated RailsController, use RailsUtil instead.
5
27
  * Fixed a bug that passing access_token in query string
data/README.rdoc CHANGED
@@ -1,4 +1,4 @@
1
- = rest-graph 1.2.1
1
+ = rest-graph 1.3.0
2
2
  by Cardinal Blue ( http://cardinalblue.com )
3
3
 
4
4
  == LINKS:
@@ -6,6 +6,7 @@ by Cardinal Blue ( http://cardinalblue.com )
6
6
  * {github}[http://github.com/cardinalblue/rest-graph]
7
7
  * {rubygems}[http://rubygems.org/gems/rest-graph]
8
8
  * {rdoc}[http://rdoc.info/projects/cardinalblue/rest-graph]
9
+ * {mailing list}[http://groups.google.com/group/rest-graph/topics]
9
10
 
10
11
  == DESCRIPTION:
11
12
 
@@ -25,21 +26,21 @@ by Cardinal Blue ( http://cardinalblue.com )
25
26
  require 'rest-graph'
26
27
 
27
28
  # Every option is optional.
28
- rg = RestGraph.new(:access_token => '...',
29
+ rg = RestGraph.new(:access_token => 'tok',
29
30
  :graph_server => 'https://graph.facebook.com/',
30
- :fql_server => 'https://api.facebook.com/',
31
+ :old_server => 'https://api.facebook.com/',
31
32
  :accept => 'text/javascript',
32
33
  :lang => 'en-us', # this affect search
33
- :auto_decode => true, # decode by json
34
- :app_id => '123',
35
- :secret => '1829',
34
+ :auto_decode => true , # decode by json
35
+ :app_id => '123' ,
36
+ :secret => '1829' ,
36
37
 
37
38
  # This handler callback is only called if auto_decode is set to true,
38
39
  # otherwise, it's ignored.
39
40
  :error_handler =>
40
41
  lambda{ |hash| raise ::RestGraph::Error.new(hash) },
41
42
 
42
- # You may want to do this in Rails to do debug logging:
43
+ # You might want to do this in Rails to do debug logging:
43
44
  :log_handler =>
44
45
  lambda{ |duration, url|
45
46
  Rails.logger.debug("RestGraph " \
@@ -47,34 +48,35 @@ by Cardinal Blue ( http://cardinalblue.com )
47
48
  "requesting #{url}")
48
49
  })
49
50
 
50
- # You may want to do redirect instead of raising exception, for example,
51
- # in a Rails application, you might have this private controller method:
52
- def redirect_to_authorize error = nil
53
- redirect_to @rg.authorize_url(:redirect_uri => request.url)
51
+ # You might want to do redirect instead of raising an exception,
52
+ # that is automatically redirect the user to authorization page
53
+ # if the access token is unavailable. This way, you don't have to
54
+ # check if the token is expired or not. If the token is expired,
55
+ # it will automatically do authorization again. For that purpose,
56
+ # you might want to include RestGraph::RailsUtil in your Rails'
57
+ # controller. For example:
58
+ class UserController < ApplicationController
59
+ include RestGraph::RailsUtil
60
+ before_filter :rest_graph_setup
54
61
  end
55
-
56
- # and you'll use that private method to do error handling:
57
- def setup_rest_graph
58
- @rg = RestGraph.new(:error_handler => method(:redirect_to_authorize))
59
- end
60
-
61
- # This way, you don't have to check if the token is expired or not.
62
- # If the token is expired, it will automatically do authorization again.
62
+ # Please read:
63
+ # {examples}[http://github.com/cardinalblue/rest-graph/tree/master/example].
64
+ # for more detail, and other frameworks utils wanted!
63
65
 
64
66
  # Other simple API call:
65
- rg.get('me') # GET https://graph.facebook.com/me?access_token=...
66
- rg.get('4/likes') # GET https://graph.facebook.com/4/likes?access_token=...
67
+ rg.get('me') # GET https://graph.facebook.com/me?access_token=tok
68
+ rg.get('4/likes') # GET https://graph.facebook.com/4/likes?access_token=tok
67
69
 
68
- # GET https://graph.facebook.com/search?q=taiwan&access_token=...
70
+ # GET https://graph.facebook.com/search?q=taiwan&access_token=tok
69
71
  rg.get('search', :q => 'taiwan')
70
72
 
71
- # GET https://graph.facebook.com/me?metadata=1&access_token=...
73
+ # GET https://graph.facebook.com/me?metadata=1&access_token=tok
72
74
  rg.get('me', :metadata => '1')
73
75
 
74
- # POST https://graph.facebook.com/me/feed?message=bread%21&access_token=...
76
+ # POST https://graph.facebook.com/me/feed?message=bread%21&access_token=tok
75
77
  rg.post('me/feed', :message => 'bread!')
76
78
 
77
- # for fully blown cookies hash
79
+ # For fully blown cookies hash
78
80
  rg = RestGraph.new(:app_id => '123', :secret => '1829')
79
81
  rg.parse_cookies!(cookies) # auto save access_token if sig checked
80
82
  rg.data['uid'] # => facebook uid
@@ -93,40 +95,61 @@ by Cardinal Blue ( http://cardinalblue.com )
93
95
  rg.fql_multi(:q1 => 'SELECT name FROM page WHERE page_id="123"',
94
96
  :q2 => 'SELECT name FROM page WHERE page_id="456"')
95
97
 
96
- # default setting:
97
- class RestGraph
98
- def self.default_app_id
98
+ # Setup default settings:
99
+ module MyDefaults
100
+ def default_app_id
99
101
  '456'
100
102
  end
101
103
 
102
- def self.default_secret
104
+ def default_secret
103
105
  'category theory'
104
106
  end
105
107
  end
108
+ RestGraph.send(:extend, MyDefaults)
106
109
 
107
- # auto load config
108
- require 'rest-graph'
110
+ # Automatically load config:
109
111
  require 'rest-graph/auto_load' # under Rails, load config/rest-graph.yaml
110
112
  RestGraph.new # all default options would honor config
111
113
  RestGraph.new(:app_id => '123') # default could be override as well
112
114
 
113
- # manually load config
115
+ # Manually load config:
114
116
  require 'rest-graph/load_config'
115
117
  RestGraph::LoadConfig.load_config!('path/to/rest-graph.yaml', 'env')
116
118
 
117
- # see test/config/rest-graph.yaml for an example for config
119
+ # See test/config/rest-graph.yaml for an example for config.
118
120
 
119
- # oauth utilites:
120
- # https://graph.facebook.com/oauth/authorize?client_id=...&
121
- RestGraph.new.authorize_url(:redirect_uri => '...')
121
+ # OAuth utilites:
122
+ # https://graph.facebook.com/oauth/authorize?client_id=123&
123
+ RestGraph.new.authorize_url(:redirect_uri => 'http://w3.org/')
122
124
 
123
- # get access token by:
124
- # https://graph.facebook.com/oauth/access_token?code=...&
125
+ # Get access token by:
126
+ # https://graph.facebook.com/oauth/access_token?code=edoc&
125
127
  rg = RestGraph.new
126
- rg.authorize!(:redirect_uri => '...', :code => 'zzz')
128
+ rg.authorize!(:redirect_uri => 'http://w3.org/', :code => 'edoc')
127
129
  rg.access_token # your access_token is now available
128
130
  rg.data['expires'] # other values as well
129
131
 
132
+ # Exchange old session key for access token:
133
+ # https://graph.facebook.com/oauth/exchange_sessions?sessions=...
134
+ rg.exchange_sessions(:sessions => params[:fb_sig_session_key])
135
+
136
+ # Call Facebook's old REST API:
137
+ rg.old_rest(
138
+ 'stream.publish',
139
+ { :message => 'Greetings',
140
+ :attachment => {:name => 'Wikipedia',
141
+ :href => 'http://wikipedia.org/',
142
+ :caption => 'Wikipedia says hi.',
143
+ :media => [{:type => 'image',
144
+ :src => 'http://wikipedia.org/favicon.ico',
145
+ :href => 'http://wikipedia.org/'}]
146
+ }.to_json,
147
+ :action_links => [{:text => 'Go to Wikipedia',
148
+ :href => 'http://wikipedia.org/'}
149
+ ].to_json
150
+ },
151
+ :suppress_decode => true)
152
+
130
153
  == REQUIREMENTS:
131
154
 
132
155
  * Tested with MRI 1.8.7 and 1.9.1
data/Rakefile CHANGED
@@ -41,3 +41,11 @@ task :default do
41
41
  Rake.application.options.show_task_pattern = /./
42
42
  Rake.application.display_tasks_and_comments
43
43
  end
44
+
45
+ desc 'Run example tests'
46
+ task 'test:example' => ['gem:install'] do
47
+ sh "cd example/rails; #{Gem.ruby} -S rake test"
48
+ end
49
+
50
+ desc 'Run all tests'
51
+ task 'test:all' => ['test', 'test:example']
data/TODO CHANGED
@@ -1,5 +1,4 @@
1
1
  = rest-graph todo list
2
2
 
3
- = 1.2
4
3
  * more docs?
5
4
  * more examples?
@@ -9,12 +9,70 @@ class ApplicationController < ActionController::Base
9
9
  # filter_parameter_logging :password
10
10
 
11
11
  include RestGraph::RailsUtil
12
- before_filter :setup_iframe
13
- before_filter :setup_rest_graph
12
+
13
+ before_filter :rest_graph_setup, :only => [:index, :url_for_standalone,
14
+ :url_for_view_stand,
15
+ :link_to_stand,
16
+ :redirect_stand]
17
+ before_filter :filter_canvas, :only => [:canvas, :url_for_canvas,
18
+ :url_for_view_canvas,
19
+ :link_to_canvas,
20
+ :redirect_canvas]
21
+ before_filter :filter_options, :only => [:options]
22
+ before_filter :filter_no_auto, :only => [:no_auto]
23
+ before_filter :filter_diff_app_id, :only => [:app_id]
14
24
 
15
25
  def index
16
- me = @rg.get('me')
17
- return unless me
18
- render :text => me.to_json
26
+ render :text => rest_graph.get('me').to_json
27
+ end
28
+ alias_method :canvas, :index
29
+ alias_method :options, :index
30
+
31
+ def no_auto
32
+ rest_graph.get('me')
33
+ rescue RestGraph::Error
34
+ render :text => 'XD'
35
+ end
36
+
37
+ def app_id
38
+ render :text => rest_graph.app_id
39
+ end
40
+
41
+ def url_for_standalone
42
+ render :text => url_for(:action => 'index')
43
+ end
44
+ alias_method :url_for_canvas, :url_for_standalone
45
+
46
+ def url_for_view_stand
47
+ render :inline => '<%= url_for(:action => "index") %>'
48
+ end
49
+ alias_method :url_for_view_canvas, :url_for_view_stand
50
+
51
+ def link_to_stand
52
+ render :inline => '<%= link_to("test", :action => "index") %>'
53
+ end
54
+ alias_method :link_to_canvas, :link_to_stand
55
+
56
+ def redirect_stand
57
+ redirect_to :action => 'index'
58
+ end
59
+ alias_method :redirect_canvas, :redirect_stand
60
+
61
+ private
62
+ def filter_canvas
63
+ rest_graph_setup(:canvas => true,
64
+ :auto_authorize_scope => 'publish_stream')
65
+ end
66
+
67
+ def filter_no_auto
68
+ rest_graph_setup(:auto_authorize => false)
69
+ end
70
+
71
+ def filter_diff_app_id
72
+ rest_graph_setup(:app_id => 'zzz')
73
+ end
74
+
75
+ def filter_options
76
+ rest_graph_setup(:auto_authorize_options => {:scope => 'bogus'})
19
77
  end
20
78
  end
@@ -19,7 +19,6 @@ Rails::Initializer.run do |config|
19
19
  # config.gem "hpricot", :version => '0.6', :source => "http://code.whytheluckystiff.net"
20
20
  # config.gem "sqlite3-ruby", :lib => "sqlite3"
21
21
  # config.gem "aws-s3", :lib => "aws/s3"
22
- config.gem 'rest-graph'
23
22
  config.gem 'rest-graph', :lib => 'rest-graph/auto_load'
24
23
 
25
24
  # Only load the plugins named here, in the order given (default is alphabetical).
@@ -1,5 +1,11 @@
1
1
 
2
- development:
3
- app_id: ''
4
- secret: ''
5
- canvas: ''
2
+ development: &default
3
+ app_id: '123'
4
+ secret: '456'
5
+ canvas: 'can'
6
+
7
+ production:
8
+ *default
9
+
10
+ test:
11
+ *default
@@ -31,7 +31,7 @@ ActionController::Routing::Routes.draw do |map|
31
31
  # end
32
32
 
33
33
  # You can have the root of your site routed with map.root -- just remember to delete public/index.html.
34
- map.root :controller => 'application'
34
+ map.connect ':action', :controller => 'application'
35
35
 
36
36
  # See how all your routes lay out with "rake routes"
37
37
 
data/example/rails/log ADDED
File without changes
@@ -0,0 +1,114 @@
1
+
2
+ require 'test_helper'
3
+ require 'webmock'
4
+
5
+ WebMock.disable_net_connect!
6
+
7
+ class ApplicationControllerTest < ActionController::TestCase
8
+ include WebMock
9
+
10
+ def setup
11
+ stub_request(:get, 'https://graph.facebook.com/me').
12
+ to_return(:body => '{"error":"not authorized"}')
13
+ end
14
+
15
+ def teardown
16
+ reset_webmock
17
+ end
18
+
19
+ def test_index
20
+ get(:index)
21
+ assert_response :redirect
22
+ assert_equal(
23
+ normalize_url(
24
+ 'https://graph.facebook.com/oauth/authorize?client_id=123&' \
25
+ 'scope=offline_access%2Cpublish_stream%2Cread_friendlists&' \
26
+ 'redirect_uri=http%3A%2F%2Ftest.host%2F'),
27
+ normalize_url(assigns(:rest_graph_authorize_url)))
28
+ end
29
+
30
+ def test_canvas
31
+ get(:canvas)
32
+ assert_response :success
33
+ assert_equal(
34
+ normalize_url(
35
+ 'https://graph.facebook.com/oauth/authorize?client_id=123&' \
36
+ 'scope=publish_stream&' \
37
+ 'redirect_uri=http%3A%2F%2Fapps.facebook.com%2Fcan%2Fcanvas'),
38
+ normalize_url((assigns(:rest_graph_authorize_url))))
39
+ end
40
+
41
+ def test_options
42
+ get(:options)
43
+ assert_response :redirect
44
+ assert_equal(
45
+ normalize_url(
46
+ 'https://graph.facebook.com/oauth/authorize?client_id=123&' \
47
+ 'scope=bogus&' \
48
+ 'redirect_uri=http%3A%2F%2Ftest.host%2Foptions'),
49
+ normalize_url((assigns(:rest_graph_authorize_url))))
50
+ end
51
+
52
+ def test_no_auto
53
+ get(:no_auto)
54
+ assert_response :success
55
+ assert_equal 'XD', @response.body
56
+ end
57
+
58
+ def test_app_id
59
+ get(:app_id)
60
+ assert_response :success
61
+ assert_equal 'zzz', @response.body
62
+ end
63
+
64
+ def test_url_for_standalone
65
+ get(:url_for_standalone)
66
+ assert_response :success
67
+ assert_equal 'http://test.host/', @response.body
68
+ end
69
+
70
+ def test_url_for_canvas
71
+ get(:url_for_canvas)
72
+ assert_response :success
73
+ assert_equal 'http://apps.facebook.com/can/',
74
+ @response.body
75
+ end
76
+
77
+ def test_url_for_view_stand
78
+ get(:url_for_view_stand)
79
+ assert_response :success
80
+ assert_equal '/', @response.body
81
+ end
82
+
83
+ def test_url_for_view_canvas
84
+ get(:url_for_view_canvas)
85
+ assert_response :success
86
+ assert_equal 'http://apps.facebook.com/can/',
87
+ @response.body
88
+ end
89
+
90
+ def test_link_to_stand
91
+ get(:link_to_stand)
92
+ assert_response :success
93
+ assert_equal '<a href="/">test</a>', @response.body
94
+ end
95
+
96
+ def test_link_to_canvas
97
+ get(:link_to_canvas)
98
+ assert_response :success
99
+ assert_equal '<a href="http://apps.facebook.com/can/">test</a>',
100
+ @response.body
101
+ end
102
+
103
+ def test_redirect_stand
104
+ get(:redirect_stand)
105
+ assert_response :redirect
106
+ assert_redirected_to '/'
107
+ end
108
+
109
+ def test_redirect_canvas
110
+ get(:redirect_canvas)
111
+ assert_response :redirect
112
+ assert_redirected_to 'http://apps.facebook.com/can/'
113
+ end
114
+ end
@@ -0,0 +1,13 @@
1
+ ENV["RAILS_ENV"] = "test"
2
+ require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
3
+ require 'test_help'
4
+
5
+ class ActiveSupport::TestCase
6
+ def normalize_query query
7
+ '?' + query[1..-1].split('&').sort.join('&')
8
+ end
9
+
10
+ def normalize_url url
11
+ url.sub(/\?.+/){ |query| normalize_query(query) }
12
+ end
13
+ end
data/init.rb CHANGED
@@ -1,3 +1,2 @@
1
1
 
2
- require 'rest-graph'
3
2
  require 'rest-graph/auto_load'
@@ -2,46 +2,77 @@
2
2
  require 'rest-graph'
3
3
 
4
4
  module RestGraph::RailsUtil
5
- module_function
6
- # filters for you
7
- def setup_iframe
8
- @fb_sig_in_iframe = true
5
+ module Helper
6
+ def url_for options
7
+ caller = respond_to?(:controller) ? controller : self
8
+ if caller.rest_graph_in_canvas? && options.kind_of?(Hash)
9
+ super({:host => "apps.facebook.com/#{RestGraph.default_canvas}"}.
10
+ merge(options))
11
+ else
12
+ super(options)
13
+ end
14
+ end
9
15
  end
10
16
 
11
- def setup_rest_graph
12
- rest_graph_create
17
+ def self.included controller
18
+ controller.rescue_from(::RestGraph::Error){ |exception|
19
+ logger.debug("DEBUG: RestGraph: action halt")
20
+ }
21
+ controller.send(:include, ::RestGraph::RailsUtil::Helper)
22
+ controller.helper(::RestGraph::RailsUtil::Helper)
23
+ end
24
+
25
+ def rest_graph_options
26
+ @rest_graph_options ||=
27
+ {:canvas => false,
28
+ :auto_authorize => true,
29
+ :auto_authorize_options => {},
30
+ :auto_authorize_scope =>
31
+ 'offline_access,publish_stream,read_friendlists'}
32
+ end
33
+
34
+ def rest_graph_options_new
35
+ @rest_graph_options_new ||=
36
+ {:error_handler => method(:rest_graph_authorize),
37
+ :log_handler => method(:rest_graph_log)}
38
+ end
39
+
40
+ def rest_graph_setup options={}
41
+ rest_graph_options .merge!(rest_graph_extract_options(options, :reject))
42
+ rest_graph_options_new.merge!(rest_graph_extract_options(options, :select))
13
43
 
14
44
  # exchange the code with access_token
15
45
  if params[:code]
16
- @rg.authorize!(:code => params[:code],
17
- :redirect_uri => normalized_request_uri)
46
+ rest_graph.authorize!(:code => params[:code],
47
+ :redirect_uri => rest_graph_normalized_request_uri)
18
48
  logger.debug(
19
- "DEBUG: RestGraph: detected code with #{normalized_request_uri}, " \
20
- "parsed: #{@rg.data.inspect}")
49
+ "DEBUG: RestGraph: detected code with " \
50
+ "#{rest_graph_normalized_request_uri}, " \
51
+ "parsed: #{rest_graph.data.inspect}")
21
52
  end
22
53
 
23
54
  # if the code is bad or not existed,
24
55
  # check if there's one in session,
25
56
  # meanwhile, there the sig and access_token is correct,
26
- # that means we're in the context of iframe
27
- if !@rg.authorized? && params[:session]
28
- @rg.parse_json!(params[:session])
29
- logger.debug(
30
- "DEBUG: RestGraph: detected session, parsed: #{@rg.data.inspect}")
31
-
32
- if @rg.authorized?
33
- @fb_sig_in_iframe = true
57
+ # that means we're in the context of canvas
58
+ if !rest_graph.authorized? && params[:session]
59
+ rest_graph.parse_json!(params[:session])
60
+ logger.debug("DEBUG: RestGraph: detected session, parsed:" \
61
+ " #{rest_graph.data.inspect}")
62
+
63
+ if rest_graph.authorized?
64
+ @fb_sig_in_canvas = true
34
65
  else
35
66
  logger.warn("WARN: RestGraph: bad session: #{params[:session]}")
36
67
  end
37
68
  end
38
69
 
39
- # if we're not in iframe nor code passed,
70
+ # if we're not in canvas nor code passed,
40
71
  # we could check out cookies as well.
41
- if !@rg.authorized?
42
- @rg.parse_cookies!(cookies)
43
- logger.debug(
44
- "DEBUG: RestGraph: detected cookies, parsed: #{@rg.data.inspect}")
72
+ if !rest_graph.authorized?
73
+ rest_graph.parse_cookies!(cookies)
74
+ logger.debug("DEBUG: RestGraph: detected cookies, parsed:" \
75
+ " #{rest_graph.data.inspect}")
45
76
  end
46
77
 
47
78
  # there are above 3 ways to check the user identity!
@@ -50,46 +81,57 @@ module RestGraph::RailsUtil
50
81
  end
51
82
 
52
83
  # override this if you need different app_id and secret
53
- def rest_graph_create
54
- @rg ||= RestGraph.new(:error_handler => method(:rest_graph_authorize),
55
- :log_handler => method(:rest_graph_log))
84
+ def rest_graph
85
+ @rest_graph ||= RestGraph.new(rest_graph_options_new)
56
86
  end
57
87
 
58
- def rest_graph_authorize error=nil
59
- logger.warn("WARN: RestGraph: #{error.inspect}") if error
60
-
61
- @authorize_url = @rg.authorize_url(
62
- {:redirect_uri => normalized_request_uri,
63
- :scope => rest_graph_authorize_scope}.
64
- merge(rest_graph_authorize_options))
88
+ def rest_graph_authorize error
89
+ logger.warn("WARN: RestGraph: #{error.inspect}")
65
90
 
66
- logger.debug("DEBUG: RestGraph: redirect to #{@authorize_url}")
91
+ @rest_graph_authorize_url = rest_graph.authorize_url(
92
+ {:redirect_uri => rest_graph_normalized_request_uri,
93
+ :scope => rest_graph_options[:auto_authorize_scope]}.
94
+ merge( rest_graph_options[:auto_authorize_options]))
67
95
 
68
- rest_graph_authorize_redirect
69
- return false
70
- end
96
+ logger.debug("DEBUG: RestGraph: redirect to #{@rest_graph_authorize_url}")
71
97
 
72
- # override this if you need different access scope
73
- def rest_graph_authorize_scope
74
- @rest_graph_authorize_scope ||=
75
- 'offline_access,publish_stream,read_friendlists'
98
+ rest_graph_authorize_redirect if rest_graph_options[:auto_authorize]
99
+ raise ::RestGraph::Error.new(error)
76
100
  end
77
101
 
78
102
  # override this if you want the simple redirect_to
79
103
  def rest_graph_authorize_redirect
80
- render :template => 'rest-graph/authorization'
81
- end
104
+ if !rest_graph_in_canvas?
105
+ redirect_to @rest_graph_authorize_url
82
106
 
83
- def rest_graph_authorize_options
84
- @rest_graph_authorize_options ||= {}
107
+ else
108
+ render :inline => <<-HTML
109
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
110
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
111
+ <html>
112
+ <head>
113
+ <script type="text/javascript">
114
+ window.top.location.href = '<%= @rest_graph_authorize_url %>'
115
+ </script>
116
+ <noscript>
117
+ <meta http-equiv="refresh" content="0;url=<%= h @rest_graph_authorize_url %>" />
118
+ <meta http-equiv="window-target" content="_top" />
119
+ </noscript>
120
+ </head>
121
+ <body>
122
+ <div>Please <a href="<%= h @rest_graph_authorize_url %>" target="_top">authorize</a> if this page is not automatically redirected.</div>
123
+ </body>
124
+ </html>
125
+ HTML
126
+ end
85
127
  end
86
128
 
87
129
  def rest_graph_log duration, url
88
130
  logger.debug("DEBUG: RestGraph: spent #{duration} requesting #{url}")
89
131
  end
90
132
 
91
- def normalized_request_uri
92
- if @fb_sig_in_iframe
133
+ def rest_graph_normalized_request_uri
134
+ if rest_graph_in_canvas?
93
135
  "http://apps.facebook.com/" \
94
136
  "#{RestGraph.default_canvas}#{request.request_uri}"
95
137
  else
@@ -97,6 +139,14 @@ module RestGraph::RailsUtil
97
139
  end.sub(/[\&\?]session=[^\&]+/, '').
98
140
  sub(/[\&\?]code=[^\&]+/, '')
99
141
  end
100
- end
101
142
 
102
- RestGraph::RailsController = RestGraph::RailsUtil
143
+ def rest_graph_in_canvas?
144
+ rest_graph_options[:canvas] || @fb_sig_in_canvas
145
+ end
146
+
147
+ def rest_graph_extract_options options, method
148
+ result = options.send(method){ |(k, v)| RestGraph::Attributes.member?(k) }
149
+ return result if result.kind_of?(Hash) # RUBY_VERSION >= 1.9.1
150
+ result.inject({}){ |r, (k, v)| r[k] = v; r }
151
+ end
152
+ end
@@ -1,4 +1,4 @@
1
1
 
2
2
  require 'rest-graph'
3
3
 
4
- RestGraph::VERSION = '1.2.1'
4
+ RestGraph::VERSION = '1.3.0'
data/lib/rest-graph.rb CHANGED
@@ -11,17 +11,18 @@ begin
11
11
  require 'rack'
12
12
  rescue LoadError; end
13
13
 
14
- begin
15
- require 'json'
16
- rescue LoadError
14
+ # pick a json gem if available
15
+ %w[ yajl/json_gem json json_pure ].each{ |json|
17
16
  begin
18
- require 'json_pure'
19
- rescue LoadError; end
20
- end
17
+ require json
18
+ break
19
+ rescue LoadError
20
+ end
21
+ }
21
22
 
22
23
  # the data structure used in RestGraph
23
24
  RestGraphStruct = Struct.new(:data, :auto_decode,
24
- :graph_server, :fql_server,
25
+ :graph_server, :old_server,
25
26
  :accept, :lang,
26
27
  :app_id, :secret,
27
28
  :error_handler,
@@ -47,7 +48,7 @@ class RestGraph < RestGraphStruct
47
48
  def default_data ; {} ; end
48
49
  def default_auto_decode ; true ; end
49
50
  def default_graph_server; 'https://graph.facebook.com/'; end
50
- def default_fql_server ; 'https://api.facebook.com/' ; end
51
+ def default_old_server ; 'https://api.facebook.com/' ; end
51
52
  def default_accept ; 'text/javascript' ; end
52
53
  def default_lang ; 'en-us' ; end
53
54
  def default_app_id ; nil ; end
@@ -79,52 +80,27 @@ class RestGraph < RestGraphStruct
79
80
  !!access_token
80
81
  end
81
82
 
82
- def get path, opts={}
83
- request(graph_server, path, opts, :get)
84
- end
85
-
86
- def delete path, opts={}
87
- request(graph_server, path, opts, :delete)
88
- end
89
-
90
- def post path, payload, opts={}
91
- request(graph_server, path, opts, :post, payload)
83
+ def get path, query={}, opts={}
84
+ request(graph_server, path, query, :get, nil, opts[:suppress_decode])
92
85
  end
93
86
 
94
- def put path, payload, opts={}
95
- request(graph_server, path, opts, :put, payload)
87
+ def delete path, query={}, opts={}
88
+ request(graph_server, path, query, :delete, nil, opts[:suppress_decode])
96
89
  end
97
90
 
98
- def fql query, opts={}
99
- request(fql_server, 'method/fql.query',
100
- {:query => query, :format => 'json'}.merge(opts), :get)
91
+ def post path, payload, query={}, opts={}
92
+ request(graph_server, path, query, :post, payload, opts[:suppress_decode])
101
93
  end
102
94
 
103
- def fql_multi queries, opts={}
104
- q = if queries.respond_to?(:to_json)
105
- queries.to_json
106
- else
107
- middle = queries.inject([]){ |r, (k, v)|
108
- r << "\"#{k}\":\"#{v.gsub('"','\\"')}\""
109
- }.join(',')
110
- "{#{middle}}"
111
- end
112
- request(fql_server, 'method/fql.multiquery',
113
- {:queries => q, :format => 'json'}.merge(opts), :get)
95
+ def put path, payload, query={}, opts={}
96
+ request(graph_server, path, query, :put, payload, opts[:suppress_decode])
114
97
  end
115
98
 
116
99
  # cookies, app_id, secrect related below
117
100
 
118
- if RUBY_VERSION >= '1.9.1'
119
- def parse_rack_env! env
120
- self.data = env['HTTP_COOKIE'] =~ /fbs_#{app_id}=([^\;]+)/ &&
121
- check_sig_and_return_data(Rack::Utils.parse_query($1))
122
- end
123
- else
124
- def parse_rack_env! env
125
- self.data = (env['HTTP_COOKIE'] || '') =~ /fbs_#{app_id}=([^\;]+)/ &&
126
- check_sig_and_return_data(Rack::Utils.parse_query($1))
127
- end
101
+ def parse_rack_env! env
102
+ env['HTTP_COOKIE'].to_s =~ /fbs_#{app_id}=([^\;]+)/
103
+ self.data = parse_fbs!($1)
128
104
  end
129
105
 
130
106
  def parse_cookies! cookies
@@ -132,13 +108,14 @@ class RestGraph < RestGraphStruct
132
108
  end
133
109
 
134
110
  def parse_fbs! fbs
135
- self.data = fbs &&
136
- check_sig_and_return_data(Rack::Utils.parse_query(fbs))
111
+ self.data = check_sig_and_return_data(
112
+ # take out facebook sometimes there but sometimes not quotes in cookies
113
+ Rack::Utils.parse_query(fbs.to_s.gsub('"', '')))
137
114
  end
138
115
 
139
116
  def parse_json! json
140
117
  self.data = json &&
141
- check_sig_and_return_data(JSON.load(json))
118
+ check_sig_and_return_data(JSON.parse(json))
142
119
  rescue JSON::ParserError
143
120
  end
144
121
 
@@ -155,13 +132,42 @@ class RestGraph < RestGraphStruct
155
132
  request(graph_server, 'oauth/access_token', query, :get, nil, true))
156
133
  end
157
134
 
135
+ # old rest facebook api, i will definitely love to remove them someday
136
+
137
+ def old_rest path, query={}, opts={}
138
+ request(old_server, "method/#{path}",
139
+ {:format => 'json'}.merge(query), :get, nil, opts[:suppress_decode])
140
+ end
141
+
142
+ def exchange_sessions opts={}
143
+ query = {:client_id => app_id, :client_secret => secret,
144
+ :type => 'client_cred'}.merge(opts)
145
+ request(graph_server, 'oauth/exchange_sessions', query, :post)
146
+ end
147
+
148
+ def fql code, query={}, opts={}
149
+ old_rest('fql.query', {:query => code}.merge(query), opts)
150
+ end
151
+
152
+ def fql_multi codes, query={}, opts={}
153
+ c = if codes.respond_to?(:to_json)
154
+ codes.to_json
155
+ else
156
+ middle = codes.inject([]){ |r, (k, v)|
157
+ r << "\"#{k}\":\"#{v.gsub('"','\\"')}\""
158
+ }.join(',')
159
+ "{#{middle}}"
160
+ end
161
+ old_rest('fql.multiquery', {:queries => c}.merge(query), opts)
162
+ end
163
+
158
164
  private
159
- def request server, path, opts, method, payload=nil, suppress_decode=false
165
+ def request server, path, opts, method, payload=nil, suppress_decode=nil
160
166
  start_time = Time.now
161
167
  res = RestClient::Resource.new(server)[path + build_query_string(opts)]
162
168
  post_request(
163
169
  res.send(method, *[payload, build_headers].compact), suppress_decode)
164
- rescue RestClient::InternalServerError => e
170
+ rescue RestClient::Exception => e
165
171
  post_request(e.http_body, suppress_decode)
166
172
  ensure
167
173
  log_handler.call(Time.now - start_time, res.url)
@@ -181,7 +187,7 @@ class RestGraph < RestGraphStruct
181
187
  headers
182
188
  end
183
189
 
184
- def post_request result, suppress_decode=false
190
+ def post_request result, suppress_decode=nil
185
191
  if auto_decode && !suppress_decode
186
192
  check_error(JSON.parse(result))
187
193
  else
data/rest-graph.gemspec CHANGED
@@ -2,22 +2,22 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{rest-graph}
5
- s.version = "1.2.1"
5
+ s.version = "1.3.0"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Cardinal Blue", "Lin Jen-Shin (aka godfat 真常)"]
9
- s.date = %q{2010-06-02}
9
+ s.date = %q{2010-06-10}
10
10
  s.description = %q{ A super simple Facebook Open Graph API client}
11
11
  s.email = %q{dev (XD) cardinalblue.com}
12
- s.extra_rdoc_files = ["CHANGES", "LICENSE", "TODO", "example/rails/README", "example/rails/app/views/rest-graph/authorization.erb", "example/rails/config/rest-graph.yaml", "example/rails/script/console", "example/rails/script/server", "rest-graph.gemspec"]
13
- s.files = ["CHANGES", "LICENSE", "README.rdoc", "Rakefile", "TODO", "example/rails/README", "example/rails/Rakefile", "example/rails/app/controllers/application_controller.rb", "example/rails/app/views/rest-graph/authorization.erb", "example/rails/config/boot.rb", "example/rails/config/environment.rb", "example/rails/config/environments/development.rb", "example/rails/config/environments/production.rb", "example/rails/config/environments/test.rb", "example/rails/config/initializers/cookie_verification_secret.rb", "example/rails/config/initializers/new_rails_defaults.rb", "example/rails/config/initializers/session_store.rb", "example/rails/config/rest-graph.yaml", "example/rails/config/routes.rb", "example/rails/script/console", "example/rails/script/server", "init.rb", "lib/rest-graph.rb", "lib/rest-graph/auto_load.rb", "lib/rest-graph/load_config.rb", "lib/rest-graph/rails_util.rb", "lib/rest-graph/version.rb", "rest-graph.gemspec", "test/common.rb", "test/config/rest-graph.yaml", "test/test_default.rb", "test/test_fql.rb", "test/test_handler.rb", "test/test_load_config.rb", "test/test_oauth.rb", "test/test_parse.rb", "test/test_rest-graph.rb"]
12
+ s.extra_rdoc_files = ["CHANGES", "LICENSE", "TODO", "example/rails/README", "example/rails/config/rest-graph.yaml", "example/rails/log", "example/rails/script/console", "example/rails/script/server", "rest-graph.gemspec"]
13
+ s.files = ["CHANGES", "LICENSE", "README.rdoc", "Rakefile", "TODO", "example/rails/README", "example/rails/Rakefile", "example/rails/app/controllers/application_controller.rb", "example/rails/config/boot.rb", "example/rails/config/environment.rb", "example/rails/config/environments/development.rb", "example/rails/config/environments/production.rb", "example/rails/config/environments/test.rb", "example/rails/config/initializers/cookie_verification_secret.rb", "example/rails/config/initializers/new_rails_defaults.rb", "example/rails/config/initializers/session_store.rb", "example/rails/config/rest-graph.yaml", "example/rails/config/routes.rb", "example/rails/log", "example/rails/script/console", "example/rails/script/server", "example/rails/test/functional/application_controller_test.rb", "example/rails/test/test_helper.rb", "init.rb", "lib/rest-graph.rb", "lib/rest-graph/auto_load.rb", "lib/rest-graph/load_config.rb", "lib/rest-graph/rails_util.rb", "lib/rest-graph/version.rb", "rest-graph.gemspec", "test/common.rb", "test/config/rest-graph.yaml", "test/test_default.rb", "test/test_handler.rb", "test/test_load_config.rb", "test/test_oauth.rb", "test/test_old.rb", "test/test_parse.rb", "test/test_rest-graph.rb"]
14
14
  s.homepage = %q{http://github.com/cardinalblue/rest-graph}
15
15
  s.rdoc_options = ["--main", "README.rdoc"]
16
16
  s.require_paths = ["lib"]
17
17
  s.rubyforge_project = %q{rest-graph}
18
18
  s.rubygems_version = %q{1.3.7}
19
19
  s.summary = %q{A super simple Facebook Open Graph API client}
20
- s.test_files = ["test/test_default.rb", "test/test_fql.rb", "test/test_handler.rb", "test/test_load_config.rb", "test/test_oauth.rb", "test/test_parse.rb", "test/test_rest-graph.rb"]
20
+ s.test_files = ["test/test_default.rb", "test/test_handler.rb", "test/test_load_config.rb", "test/test_oauth.rb", "test/test_old.rb", "test/test_parse.rb", "test/test_rest-graph.rb"]
21
21
 
22
22
  if s.respond_to? :specification_version then
23
23
  current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
@@ -30,7 +30,7 @@ Gem::Specification.new do |s|
30
30
  s.add_development_dependency(%q<rr>, [">= 0.10.11"])
31
31
  s.add_development_dependency(%q<webmock>, [">= 1.2.2"])
32
32
  s.add_development_dependency(%q<bacon>, [">= 1.1.0"])
33
- s.add_development_dependency(%q<bones>, [">= 3.4.3"])
33
+ s.add_development_dependency(%q<bones>, [">= 3.4.6"])
34
34
  else
35
35
  s.add_dependency(%q<rest-client>, [">= 1.5.1"])
36
36
  s.add_dependency(%q<json>, [">= 1.4.3"])
@@ -38,7 +38,7 @@ Gem::Specification.new do |s|
38
38
  s.add_dependency(%q<rr>, [">= 0.10.11"])
39
39
  s.add_dependency(%q<webmock>, [">= 1.2.2"])
40
40
  s.add_dependency(%q<bacon>, [">= 1.1.0"])
41
- s.add_dependency(%q<bones>, [">= 3.4.3"])
41
+ s.add_dependency(%q<bones>, [">= 3.4.6"])
42
42
  end
43
43
  else
44
44
  s.add_dependency(%q<rest-client>, [">= 1.5.1"])
@@ -47,6 +47,6 @@ Gem::Specification.new do |s|
47
47
  s.add_dependency(%q<rr>, [">= 0.10.11"])
48
48
  s.add_dependency(%q<webmock>, [">= 1.2.2"])
49
49
  s.add_dependency(%q<bacon>, [">= 1.1.0"])
50
- s.add_dependency(%q<bones>, [">= 3.4.3"])
50
+ s.add_dependency(%q<bones>, [">= 3.4.6"])
51
51
  end
52
52
  end
@@ -35,11 +35,16 @@ describe RestGraph do
35
35
  f1 = 'SELECT display_name FROM application WHERE app_id="110225210740"'
36
36
  f0q, f1q = "\"#{f0.gsub('"', '\\"')}\"", "\"#{f1.gsub('"', '\\"')}\""
37
37
  q = "format=json&queries=#{CGI.escape("{\"f0\":#{f0q},\"f1\":#{f1q}}")}"
38
+ p = "format=json&queries=#{CGI.escape("{\"f1\":#{f1q},\"f0\":#{f0q}}")}"
38
39
 
39
40
  stub_multi = lambda{
40
41
  stub_request(:get,
41
42
  "https://api.facebook.com/method/fql.multiquery?#{q}").
42
43
  to_return(:body => '[]')
44
+
45
+ stub_request(:get,
46
+ "https://api.facebook.com/method/fql.multiquery?#{p}").
47
+ to_return(:body => '[]')
43
48
  }
44
49
 
45
50
  stub_multi.call
@@ -57,4 +62,27 @@ describe RestGraph do
57
62
  stub_multi.call
58
63
  RestGraph.new.fql_multi(queries).should == []
59
64
  end
65
+
66
+ it 'would do facebook old rest api' do
67
+ body = 'hate facebook inconsistent'
68
+ stub_request(:get,
69
+ 'https://api.facebook.com/method/notes.create?format=json').
70
+ to_return(:body => body)
71
+
72
+ RestGraph.new.old_rest('notes.create', {}, :suppress_decode => true).
73
+ should == body
74
+ end
75
+
76
+ it 'would exchange sessions for access token' do
77
+ stub_request(:post,
78
+ 'https://graph.facebook.com/oauth/exchange_sessions?' \
79
+ 'type=client_cred&client_id=id&client_secret=di&' \
80
+ 'sessions=bad%20bed').
81
+ to_return(:body => '[{"access_token":"bogus"}]')
82
+
83
+ RestGraph.new(:app_id => 'id',
84
+ :secret => 'di').
85
+ exchange_sessions(:sessions => 'bad bed').
86
+ first['access_token'].should == 'bogus'
87
+ end
60
88
  end
data/test/test_parse.rb CHANGED
@@ -21,7 +21,7 @@ describe RestGraph do
21
21
  fbs = "access_token=#{CGI.escape(access_token)}&expires=0&" \
22
22
  "secret=abc&session_key=def-456&sig=#{sig}&uid=3"
23
23
 
24
- check = lambda{ |token|
24
+ check = lambda{ |token, fbs|
25
25
  http_cookie =
26
26
  "__utma=123; __utmz=456.utmcsr=(d)|utmccn=(d)|utmcmd=(n); " \
27
27
  "fbs_#{app_id}=#{fbs}"
@@ -42,10 +42,11 @@ describe RestGraph do
42
42
  should.kind_of?(token ? Hash : NilClass)
43
43
  rg.access_token.should == token
44
44
  }
45
- check.call(access_token)
46
- fbs.chop!
47
- fbs += '&inject=evil"'
48
- check.call(nil)
45
+ check.call(access_token, fbs)
46
+ check.call(access_token, "\"#{fbs}\"")
47
+ fbs << '&inject=evil"'
48
+ check.call(nil, fbs)
49
+ check.call(nil, "\"#{fbs}\"")
49
50
  end
50
51
 
51
52
  it 'would not pass if there is no secret, prevent from forgery' do
@@ -75,20 +75,31 @@ describe RestGraph do
75
75
  should == '[]'
76
76
  end
77
77
 
78
+ it 'could suppress auto-decode in an api call' do
79
+ stub_request(:get, 'https://graph.facebook.com/woot').
80
+ to_return(:body => 'bad json')
81
+
82
+ rg = RestGraph.new(:auto_decode => true)
83
+ rg.get('woot', {}, :suppress_decode => true).should == 'bad json'
84
+ rg.auto_decode.should == true
85
+ end
86
+
78
87
  it 'would call post_request after request' do
79
88
  stub_request(:put, 'https://graph.facebook.com/feed/me').
80
89
  with(:body => 'message=hi%20there').to_return(:body => '[]')
81
90
 
82
- mock.proxy(rg = RestGraph.new).post_request('[]', false)
91
+ mock.proxy(rg = RestGraph.new).post_request('[]', nil)
83
92
  rg.put('feed/me', :message => 'hi there').
84
93
  should == []
85
94
  end
86
95
 
87
- it 'would not raise exception when encountering 500' do
88
- stub_request(:delete, 'https://graph.facebook.com/123').to_return(
89
- :body => '[]', :status => 500)
96
+ it 'would not raise exception when encountering error' do
97
+ [500, 401, 402, 403].each{ |status|
98
+ stub_request(:delete, 'https://graph.facebook.com/123').to_return(
99
+ :body => '[]', :status => status)
90
100
 
91
- RestGraph.new.delete('123').should == []
101
+ RestGraph.new.delete('123').should == []
102
+ }
92
103
  end
93
104
 
94
105
  it 'would return true in authorized? if there is an access_token' do
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rest-graph
3
3
  version: !ruby/object:Gem::Version
4
- hash: 29
4
+ hash: 27
5
5
  prerelease: false
6
6
  segments:
7
7
  - 1
8
- - 2
9
- - 1
10
- version: 1.2.1
8
+ - 3
9
+ - 0
10
+ version: 1.3.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Cardinal Blue
@@ -16,7 +16,7 @@ autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
18
 
19
- date: 2010-06-02 00:00:00 +08:00
19
+ date: 2010-06-11 00:00:00 +08:00
20
20
  default_executable:
21
21
  dependencies:
22
22
  - !ruby/object:Gem::Dependency
@@ -123,12 +123,12 @@ dependencies:
123
123
  requirements:
124
124
  - - ">="
125
125
  - !ruby/object:Gem::Version
126
- hash: 17
126
+ hash: 27
127
127
  segments:
128
128
  - 3
129
129
  - 4
130
- - 3
131
- version: 3.4.3
130
+ - 6
131
+ version: 3.4.6
132
132
  type: :development
133
133
  version_requirements: *id007
134
134
  description: " A super simple Facebook Open Graph API client"
@@ -142,8 +142,8 @@ extra_rdoc_files:
142
142
  - LICENSE
143
143
  - TODO
144
144
  - example/rails/README
145
- - example/rails/app/views/rest-graph/authorization.erb
146
145
  - example/rails/config/rest-graph.yaml
146
+ - example/rails/log
147
147
  - example/rails/script/console
148
148
  - example/rails/script/server
149
149
  - rest-graph.gemspec
@@ -156,7 +156,6 @@ files:
156
156
  - example/rails/README
157
157
  - example/rails/Rakefile
158
158
  - example/rails/app/controllers/application_controller.rb
159
- - example/rails/app/views/rest-graph/authorization.erb
160
159
  - example/rails/config/boot.rb
161
160
  - example/rails/config/environment.rb
162
161
  - example/rails/config/environments/development.rb
@@ -167,8 +166,11 @@ files:
167
166
  - example/rails/config/initializers/session_store.rb
168
167
  - example/rails/config/rest-graph.yaml
169
168
  - example/rails/config/routes.rb
169
+ - example/rails/log
170
170
  - example/rails/script/console
171
171
  - example/rails/script/server
172
+ - example/rails/test/functional/application_controller_test.rb
173
+ - example/rails/test/test_helper.rb
172
174
  - init.rb
173
175
  - lib/rest-graph.rb
174
176
  - lib/rest-graph/auto_load.rb
@@ -179,10 +181,10 @@ files:
179
181
  - test/common.rb
180
182
  - test/config/rest-graph.yaml
181
183
  - test/test_default.rb
182
- - test/test_fql.rb
183
184
  - test/test_handler.rb
184
185
  - test/test_load_config.rb
185
186
  - test/test_oauth.rb
187
+ - test/test_old.rb
186
188
  - test/test_parse.rb
187
189
  - test/test_rest-graph.rb
188
190
  has_rdoc: true
@@ -222,9 +224,9 @@ specification_version: 3
222
224
  summary: A super simple Facebook Open Graph API client
223
225
  test_files:
224
226
  - test/test_default.rb
225
- - test/test_fql.rb
226
227
  - test/test_handler.rb
227
228
  - test/test_load_config.rb
228
229
  - test/test_oauth.rb
230
+ - test/test_old.rb
229
231
  - test/test_parse.rb
230
232
  - test/test_rest-graph.rb
@@ -1,16 +0,0 @@
1
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3
- <html>
4
- <head>
5
- <script type="text/javascript">
6
- window.top.location.href = '<%= @authorize_url %>'
7
- </script>
8
- <noscript>
9
- <meta http-equiv="refresh" content="0;url=<%= h @authorize_url %>" />
10
- <meta http-equiv="window-target" content="_top" />
11
- </noscript>
12
- </head>
13
- <body>
14
- <div>Please <a href="<%= h @authorize_url %>" target="_top">authorize</a> if this page is not automatically redirected.</div>
15
- </body>
16
- </html>