require 'rest-graph'
class RestGraph
module DefaultAttributes
def default_canvas ; '' ; end
def default_auto_authorize ; false; end
def default_auto_authorize_options; {} ; end
def default_auto_authorize_scope ; '' ; end
def default_write_session ; false; end
end
module RailsCache
def [] key ; read(key) ; end
def []= key, value; write(key, value); end
end
end
::ActiveSupport::Cache::Store.send(:include, ::RestGraph::RailsCache)
module RestGraph::RailsUtil
module Helper
def rest_graph
controller.rest_graph
end
end
def self.included controller
controller.rescue_from(::RestGraph::Error){ |exception|
logger.debug("DEBUG: RestGraph: action halt")
}
controller.helper(::RestGraph::RailsUtil::Helper)
end
def rest_graph_setup options={}
rest_graph_options_ctl.merge!(rest_graph_extract_options(options, :reject))
rest_graph_options_new.merge!(rest_graph_extract_options(options, :select))
rest_graph_check_cookie
rest_graph_check_params_signed_request
rest_graph_check_params_session
rest_graph_check_code
# there are above 4 ways to check the user identity!
# if nor of them passed, then we can suppose the user
# didn't authorize for us, but we can check if user has authorized
# before, in that case, the fbs would be inside session,
# as we just saved it there
rest_graph_check_rails_session
end
# override this if you need different app_id and secret
def rest_graph
@rest_graph ||= RestGraph.new(rest_graph_options_new)
end
def rest_graph_authorize error=nil, redirect=false
logger.warn("WARN: RestGraph: #{error.inspect}")
if redirect || rest_graph_auto_authorize?
@rest_graph_authorize_url = rest_graph.authorize_url(
{:redirect_uri => rest_graph_normalized_request_uri,
:scope => rest_graph_oget(:auto_authorize_scope)}.
merge(rest_graph_oget(:auto_authorize_options)))
logger.debug("DEBUG: RestGraph: redirect to #{@rest_graph_authorize_url}")
rest_graph_authorize_redirect
end
raise ::RestGraph::Error.new(error)
end
# override this if you want the simple redirect_to
def rest_graph_authorize_redirect
if !rest_graph_in_canvas?
redirect_to @rest_graph_authorize_url
else
render :inline => <<-HTML
Please authorize if this page is not automatically redirected.
HTML
end
end
module_function
# ==================== options utility =======================
def rest_graph_oget key
if rest_graph_options_ctl.has_key?(key)
rest_graph_options_ctl[key]
else
RestGraph.send("default_#{key}")
end
end
def rest_graph_options_ctl
@rest_graph_options_ctl ||= {}
end
def rest_graph_options_new
@rest_graph_options_new ||=
{:error_handler => method(:rest_graph_authorize),
:log_handler => method(:rest_graph_log)}
end
# ==================== checking utility ======================
# if we're not in canvas nor code passed,
# we could check out cookies as well.
def rest_graph_check_cookie
return if rest_graph.authorized? ||
!cookies["fbs_#{rest_graph.app_id}"]
rest_graph.parse_cookies!(cookies)
logger.debug("DEBUG: RestGraph: detected cookies, parsed:" \
" #{rest_graph.data.inspect}")
end
def rest_graph_check_params_signed_request
return if rest_graph.authorized? || !params[:signed_request]
rest_graph.parse_signed_request!(params[:signed_request])
logger.debug("DEBUG: RestGraph: detected signed_request, parsed:" \
" #{rest_graph.data.inspect}")
if rest_graph.authorized?
rest_graph_write_session
else
logger.warn(
"WARN: RestGraph: bad signed_request: #{params[:signed_request]}")
end
end
# if the code is bad or not existed,
# check if there's one in session,
# meanwhile, there the sig and access_token is correct,
# that means we're in the context of canvas
def rest_graph_check_params_session
return if rest_graph.authorized? || !params[:session]
rest_graph.parse_json!(params[:session])
logger.debug("DEBUG: RestGraph: detected session, parsed:" \
" #{rest_graph.data.inspect}")
if rest_graph.authorized?
rest_graph_write_session
else
logger.warn("WARN: RestGraph: bad session: #{params[:session]}")
end
end
# exchange the code with access_token
def rest_graph_check_code
return if rest_graph.authorized? || !params[:code]
rest_graph.authorize!(:code => params[:code],
:redirect_uri => rest_graph_normalized_request_uri)
logger.debug(
"DEBUG: RestGraph: detected code with " \
"#{rest_graph_normalized_request_uri}, " \
"parsed: #{rest_graph.data.inspect}")
rest_graph_write_session if rest_graph.authorized?
end
def rest_graph_check_rails_session
return if rest_graph.authorized? || !session['fbs']
rest_graph.parse_fbs!(session['fbs'])
logger.debug("DEBUG: RestGraph: detected session, parsed:" \
" #{rest_graph.data.inspect}")
end
# ==================== others ================================
def rest_graph_write_session
return if !rest_graph_oget(:write_session)
fbs = rest_graph.data.to_a.map{ |k_v| k_v.join('=') }.join('&')
session['fbs'] = fbs
logger.debug("DEBUG: RestGraph: wrote session: fbs => #{fbs}")
end
def rest_graph_log event
message = "DEBUG: RestGraph: spent #{sprintf('%f', event.duration)} "
case event
when RestGraph::Event::Requested
logger.debug(message + "requesting #{event.url}")
when RestGraph::Event::CacheHit
logger.debug(message + "cache hit' #{event.url}")
end
end
def rest_graph_normalized_request_uri
if rest_graph_in_canvas?
"http://apps.facebook.com/" \
"#{rest_graph_oget(:canvas)}#{request.request_uri}"
else
request.url
end.sub(/[\&\?]session=[^\&]+/, '').
sub(/[\&\?]code=[^\&]+/, '')
end
def rest_graph_in_canvas?
!rest_graph_oget(:canvas).blank?
end
def rest_graph_auto_authorize?
!rest_graph_oget(:auto_authorize_scope) .blank? ||
!rest_graph_oget(:auto_authorize_options).blank? ||
rest_graph_oget(:auto_authorize)
end
def rest_graph_extract_options options, method
result = options.send(method){ |(k, v)| RestGraph::Attributes.member?(k) }
return result if result.kind_of?(Hash) # RUBY_VERSION >= 1.9.1
result.inject({}){ |r, (k, v)| r[k] = v; r }
end
end