Skip to content

Instantly share code, notes, and snippets.

@pwnall
Created June 6, 2010 17:41
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save pwnall/427739 to your computer and use it in GitHub Desktop.
# Wraps an OAuth2 access token for Facebook.
class FacebookToken < ActiveRecord::Base
# The user whose token this is.
belongs_to :user
validates :user, :presence => true
# A unique ID on the Facebook site for the user owning this token.
validates :external_uid, :length => 1..32, :presence => true
# The OAuth2 access token.
validates :access_token, :length => 1..128, :presence => true
# FBGraph client loaded with this access token.
def facebook_client
@client ||= FBGraphRails.fbclient(access_token)
end
# Finds or creates the model containing a token.
#
# If a model for the same user exists, the model is updated with the given
# token. Otherwise, a new model will be created, together with a user.
def self.for(access_token)
uid = uid_from_token access_token
token = self.where(:external_uid => uid).first
if token
token.access_token = access_token
else
token = FacebookToken.new :external_uid => uid,
:access_token => access_token
token.user = User.create_with_facebook_token token
end
token.save!
token
end
# Extracts the Facebook user ID from a OAuth2 token.
#
# This is a hack. It works based on the current format, but might break at any
# time. Hopefully, we'll eventually have an official way of pulling the UID
# out of an OAuth2 token.
def self.uid_from_token(access_token)
access_token.split('|')[1].split('-').last
end
end
# :nodoc: methods based on the Facebook API
class FacebookToken
# The albums belonging to this Facebook account.
#
# Returns an array with one Hash per album. Hashes have the following keys:
# :name:: the album's name
# :count:: the number of photos in the album
# :thumbnail:: a URL to the thumbnail of the album's main photo
def albums
facebook_client.selection.me.albums.limit(200).info!['data'].map do |album|
{ :name => album['name'], :id => album['id'],
:count => album['count'].to_i,
:thumbnail => facebook_client.selection.album(album['id']).picture }
end
end
# The photos in a Facebook album.
#
# Args:
# album_id:: the OpenGraph ID for the album to be enumerated
# photo_limit:: the maximum number of photos to be retrieved
#
# Returns an array with one Hash per photo. Hashes have the following keys:
# :name:: the photo's caption
# :id:: the photo's OpenGraph ID
# :thumbnail:: a URL to the photo's thumbnail
# :full:: a URL to the photo's full-size rendering
def photos_in_album(album_id, photo_limit = 200)
if album_id.to_s == external_uid.to_s
# NOTE: this is a workaround against a Facebook API bug:
# http://bugs.developers.facebook.com/show_bug.cgi?id=10083
profile_id = external_uid.to_i
# http://wiki.developers.facebook.com/index.php/Profile_archive_album
aid = (profile_id < (1 << 32)) ?
((profile_id << 32) | ((1 << 32) - 3)).to_s :
"#{profile_id}_-3"
uri = "https://api.facebook.com/method/photos.get?access_token=" +
"#{URI.escape(access_token)}&aid=#{URI.escape aid}"
nokogiri = Nokogiri.parse Curl::Easy.perform(uri).body_str
nokogiri.css('photo').map do |photo|
{ :name => photo.css('caption').first.inner_text,
:id => photo.css('pid').first.inner_text,
:thumbnail => photo.css('src_small').first.inner_text,
:full => photo.css('src_big').first.inner_text }
end
else
facebook_client.selection.album(album_id).photos.
limit(photo_limit).info!['data'].map do |photo|
{ :name => photo['name'], :id => photo['id'],
:thumbnail => photo['picture'], :full => photo['source'] }
end
end
end
# The photos that the token's owner is tagged in.
#
# Args:
# photo_limit:: the maximum number of photos to be retrieved
#
# Returns an array with one Hash per photo. Hashes have the following keys:
# :name:: the photo's caption
# :id:: the photo's OpenGraph ID
# :thumbnail:: a URL to the photo's thumbnail
# :full:: a URL to the photo's full-size rendering
def photos_of_self(photo_limit = 200)
facebook_client.selection.me.photos.limit(photo_limit).
info!['data'].map do |photo|
{ :name => photo['name'], :id => photo['id'],
:thumbnail => photo['picture'], :full => photo['source'] }
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment