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