module AuthlogicFacebookConnect module Session def self.included(klass) klass.class_eval do extend Config include Methods end end module Config # Should the user be saved with our without validations? # # The default behavior is to save the user without validations and then # in an application specific interface ask for the additional user # details to make the user valid as facebook just provides a facebook id. # # This is useful if you do want to turn on user validations, maybe if you # just have facebook connect as an additional authentication solution and # you already have valid users. # # * Default: true # * Accepts: Boolean def facebook_valid_user(value = nil) rw_config(:facebook_valid_user, value, false) end alias_method :facebook_valid_user=, :facebook_valid_user # What user field should be used for the facebook UID? # # This is useful if you want to use a single field for multiple types of # alternate user IDs, e.g. one that handles both OpenID identifiers and # facebook ids. # # * Default: :facebook_uid # * Accepts: Symbol def facebook_uid_field(value = nil) rw_config(:facebook_uid_field, value, :facebook_uid) end alias_method :facebook_uid_field=, :facebook_uid_field # Class representing facebook users we want to authenticate against # # * Default: klass # * Accepts: Class def facebook_user_class(value = nil) rw_config(:facebook_user_class, value, klass) end alias_method :facebook_user_class=, :facebook_user_class # Should a new user creation be skipped if there is no user with given facebook uid? # # The default behavior is not to skip (hence create new user). You may want to turn it on # if you want to try with different model. # # * Default: false # * Accepts: Boolean def facebook_skip_new_user_creation(value = nil) rw_config(:facebook_skip_new_user_creation, value, false) end alias_method :facebook_skip_new_user_creation=, :facebook_skip_new_user_creation end module Methods def self.included(klass) klass.class_eval do validate :validate_by_facebook_connect, :if => :authenticating_with_facebook_connect? end def credentials=(value) # TODO: Is there a nicer way to tell Authlogic that we don't have any credentials than this? values = [:facebook_connect] super end end def validate_by_facebook_connect facebook_session = controller.facebook_session self.attempted_record = facebook_user_class.find(:first, :conditions => { facebook_uid_field => facebook_session.user.uid }).try(:"#{klass}".to_s.underscore) unless self.attempted_record || facebook_skip_new_user_creation begin # Get the user from facebook and create a local user. # # We assign it after the call to new in case the attribute is protected. new_user = klass.new if klass == facebook_user_class new_user.send(:"#{facebook_uid_field}=", facebook_session.user.uid) else new_user.send(:"build_#{facebook_user_class.to_s.underscore}", :"#{facebook_uid_field}" => facebook_session.user.uid) end new_user.before_connect(facebook_session) if new_user.respond_to?(:before_connect) self.attempted_record = new_user if facebook_valid_user errors.add_to_base( I18n.t('error_messages.facebook_user_creation_failed', :default => 'There was a problem creating a new user ' + 'for your Facebook account')) unless self.attempted_record.valid? self.attempted_record = nil else self.attempted_record.save_with_validation(false) end rescue Facebooker::Session::SessionExpired errors.add_to_base(I18n.t('error_messages.facebooker_session_expired', :default => "Your Facebook Connect session has expired, please reconnect.")) end end end def authenticating_with_facebook_connect? controller.set_facebook_session attempted_record.nil? && errors.empty? && controller.facebook_session end private def facebook_valid_user self.class.facebook_valid_user end def facebook_uid_field self.class.facebook_uid_field end def facebook_user_class self.class.facebook_user_class end def facebook_skip_new_user_creation self.class.facebook_skip_new_user_creation end end end end