From 34b4d300144e088cc8fb45ecb44d243c8d42e482 Mon Sep 17 00:00:00 2001 From: Daniel O'Connor Date: Fri, 21 Aug 2015 13:22:49 +0930 Subject: [PATCH] #645 Enable account creation or authorisation from a facebook signin (and should work for others with minimal extra work) --- .../omniauth_callbacks_controller.rb | 90 +++++++++++++++++++ config/initializers/devise.rb | 2 +- config/routes.rb | 2 +- 3 files changed, 92 insertions(+), 2 deletions(-) create mode 100644 app/controllers/omniauth_callbacks_controller.rb diff --git a/app/controllers/omniauth_callbacks_controller.rb b/app/controllers/omniauth_callbacks_controller.rb new file mode 100644 index 000000000..6cfc98cc0 --- /dev/null +++ b/app/controllers/omniauth_callbacks_controller.rb @@ -0,0 +1,90 @@ +# +# Handle signup or signin +# from various oauth providers +# +# Heavily overlaps with Authentications controller +# +class OmniauthCallbacksController < Devise::OmniauthCallbacksController + def facebook + create + end + def failure + redirect_to request.env['omniauth.origin'] || "/", :flash => {:error => ":("} + end + + private + + # + # Inspects the omniauth information + # and determines if we have an existing member + # (to add authentication to) + # or if this is a new signup + # + # As a side affect, this method sets the @member_created + # variable + # + def member + @member_created = false + + auth = request.env['omniauth.auth'] + + authentication = Authentication.where(provider: auth.provider, uid: auth.uid).first + if authentication && authentication.member.id.present? + member = authentication.member + end + + Member.where(email: auth.info.email).first_or_create do |m| + m.email = auth.info.email + m.password = Devise.friendly_token[0,20] + m.tos_agreement = true + m.login_name = Devise.friendly_token[0,20] # TODO: A better login name to generate + + # m.name = auth.info.name # assuming the user model has a name + # m.image = auth.info.image # assuming the user model has an image + @member_created = true + end + + member + end + + def create + auth = request.env['omniauth.auth'] + @authentication = nil + if auth + + name = '' + case auth['provider'] + when 'twitter' + name = auth['info']['nickname'] + when 'flickr', 'facebook' + name = auth['info']['name'] + else + name = auth['info']['name'] + end + + @authentication = member.authentications + .create_with( + :name => name, + :token => auth['credentials']['token'], + :secret => auth['credentials']['secret'], + ) + .find_or_create_by( + :provider => auth['provider'], + :uid => auth['uid'], + :name => name, + :member_id => member.id + ) + + unless @member_created + sign_in_and_redirect member, :event => :authentication #this will throw if @user is not activated + set_flash_message(:notice, :success, :kind => auth['provider']) if is_navigational_format? + else + session["devise.#{auth['provider']}_data"] = request.env["omniauth.auth"] + redirect_to new_member_registration_url + end + else + flash[:notice] = "Authentication failed." + redirect_to request.env['omniauth.origin'] || edit_member_registration_path + end + end +end \ No newline at end of file diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index 85136c5df..f372c9190 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -231,5 +231,5 @@ Devise.setup do |config| # When using omniauth, Devise cannot automatically set Omniauth path, # so you need to do it manually. For the users scope, it would be: # config.omniauth_path_prefix = "/my_engine/users/auth" - config.omniauth :facebook, ENV['GROWSTUFF_FACEBOOK_KEY'], ENV['GROWSTUFF_FACEBOOK_SECRET'], :scope => 'email', :display => 'popup' + config.omniauth :facebook, ENV['GROWSTUFF_FACEBOOK_KEY'], ENV['GROWSTUFF_FACEBOOK_SECRET'], :scope => 'email,read_stream', :display => 'page', :info_fields => 'nickname,email,name' end diff --git a/config/routes.rb b/config/routes.rb index 1aa7e772a..9c45749d3 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -4,7 +4,7 @@ Growstuff::Application.routes.draw do resources :plant_parts - devise_for :members, :controllers => { :registrations => "registrations", :passwords => "passwords" } + devise_for :members, :controllers => { :registrations => "registrations", :passwords => "passwords", :omniauth_callbacks => "omniauth_callbacks" } devise_scope :member do get '/members/unsubscribe/:message' => 'members#unsubscribe', :as => 'unsubscribe_member' end