module FBCLI

Constants

API_VERSION
VERSION

Public Class Methods

api_call(lambda) click to toggle source
# File lib/fbcli/api.rb, line 29
def self.api_call(lambda)
  @@api = init_api if @@api.nil?

  begin
    lambda.call(@@api)
  rescue Koala::Facebook::APIError => e
    exit_now! koala_error_str e
  end
end
get_access_token(app_id, auth_code, app_secret, redirect_uri) click to toggle source
# File lib/fbcli/auth.rb, line 71
def self.get_access_token(app_id, auth_code, app_secret, redirect_uri)
  # The redirect_uri doesn't play the same role as in capturing the auth code, however
  # it must match the one used in the previous case, otherwise the server will reject
  # the request.
  #
  # See: https://www.oauth.com/oauth2-servers/access-tokens/authorization-code-request/
  auth_uri = "https://graph.facebook.com/v#{API_VERSION}/oauth/access_token?" +
    "client_id=#{app_id}" +
    "&redirect_uri=#{redirect_uri}" +
    "&client_secret=#{app_secret}" +
    "&code=#{auth_code}"

  res = Net::HTTP.get_response(URI.parse(auth_uri))
  res = JSON.parse(res.body)

  res["access_token"]
end
init_api() click to toggle source
# File lib/fbcli/api.rb, line 6
  def self.init_api
    if $config['access_token'].nil? or $config['access_token'].empty?
      exit_now! <<-EOM
Obtain an access token to interact with the Facebook API.

Run: #{APP_NAME} login
      EOM
    end

    Koala::Facebook::API.new($config['access_token'])
  end
koala_error_str(e) click to toggle source
# File lib/fbcli/api.rb, line 18
def self.koala_error_str(e)
  str = "Koala #{e.fb_error_type}"
  str << " (code #{e.fb_error_code.to_s +
           (e.fb_error_subcode.nil? ? "" : ", subcode: " + e.fb_error_subcode.to_s)})"
  str << " HTTP status: #{e.http_status}" unless e.http_status.nil?
  str << "\n  #{e.fb_error_user_msg.nil? ? e.fb_error_message : e.fb_error_user_msg}"
  str << " (FB trace id: #{e.fb_error_trace_id})"

  str
end
login(app_id, app_secret, local_host, local_port) click to toggle source
# File lib/fbcli/auth.rb, line 10
  def self.login(app_id, app_secret, local_host, local_port)
    redirect_uri = "https://#{local_host}:#{local_port}/"

    uri = "https://www.facebook.com/dialog/oauth?client_id=#{app_id}" +
      "&redirect_uri=#{redirect_uri}" +
      "&scope=user_likes,user_posts,user_photos,user_videos"

    puts <<-EOM
Open this URL in a web browser and allow access to the Facebook Graph on behalf of your user account:

#{uri}

Waiting to receive authorization code on port #{local_port}...

    EOM

    server = WEBrick::HTTPServer.new(
      :Port => local_port,
      :SSLEnable => true,
      :SSLCertName => [ %w[CN localhost] ],
      :Logger => WEBrick::Log.new(File.open(File::NULL, 'w')),
      :AccessLog => []
    )

    # TODO: WEBrick generates a self-signed SSL certificate with serial number 1, which
    #       causes Firefox to complain with SEC_ERROR_REUSED_ISSUER_AND_SERIAL on the
    #       second authentication attempt.
    #
    #       See: https://github.com/ruby/webrick/blob/6e9081b/lib/webrick/ssl.rb#L112
    #
    #       Providing a self-signed certificate to WEBrick during instantiation is one
    #       way to surmount this inconvenience.

    access_token = nil

    server.mount_proc '/' do |req, res|
      key, value = req.query_string.split '=', 2

      if key == "code"
        puts "Received authorization code. Exchanging it for an access token..."
        puts

        access_token = get_access_token(app_id, value, app_secret, redirect_uri)
      else
        puts "Received unexpected request: #{req.query_string}"
      end

      res.body = 'You may now close this window.'
      server.shutdown
    end

    # Allow CTRL+C intervention
    trap 'INT' do server.shutdown end

    # Block execution on this thread until server shuts down
    server.start

    # Return access token
    access_token
  end
logout() click to toggle source
# File lib/fbcli/api.rb, line 45
def self.logout
  api_call lambda { |api|
    api.delete_object("me/permissions")
  }
end
page_items(cmd, separator = nil, filter = nil) { |item| ... } click to toggle source
# File lib/fbcli/api.rb, line 73
def self.page_items(cmd, separator = nil, filter = nil)
  items = request_personal_connections(cmd)

  virgin = true
  count = 0

  while not (items.nil? or count == $global_options['pages']) do
    items.each_with_index { |item, idx|
      if filter.nil? or not filter.call(item)
        unless separator.nil? or virgin
          puts separator
        end

        yield item

        virgin = false
      end
    }

    count += 1
    items = items.next_page
  end
end
raw_request(req) click to toggle source
# File lib/fbcli/api.rb, line 39
def self.raw_request(req)
  api_call lambda { |api|
    api.graph_call req
  }
end
request_object(id, options = {}) { |data| ... } click to toggle source
# File lib/fbcli/api.rb, line 59
def self.request_object(id, options = {})
  api_call lambda { |api|
    api.get_object(id, options) do |data|
      yield data
    end
  }
end
request_personal_connections(cmd) click to toggle source
# File lib/fbcli/api.rb, line 67
def self.request_personal_connections(cmd)
  api_call lambda { |api|
    api.get_connections("me", cmd)
  }
end
request_token_info(access_token = $config['access_token']) { |res| ... } click to toggle source
# File lib/fbcli/api.rb, line 51
def self.request_token_info(access_token = $config['access_token'])
  api_call lambda { |api|
    api.debug_token access_token do |res|
      yield res['data']
    end
  }
end