diff --git a/app/controllers/users/omniauth_callbacks_controller.rb b/app/controllers/users/omniauth_callbacks_controller.rb new file mode 100644 index 00000000..f78be6ac --- /dev/null +++ b/app/controllers/users/omniauth_callbacks_controller.rb @@ -0,0 +1,20 @@ +class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController + + User::SOCIAL_SITES.each do |name| + define_method name do + social_site + end + end + + private + + def social_site + @user = OmniauthUser.from_omniauth(request.env["omniauth.auth"], current_user) + if @user.errors.messages.present? + redirect_to user_session_path, alert: @user.errors.full_messages.first + else + flash[:notice] = I18n.t 'devise.omniauth_callbacks.success', kind: request.env["omniauth.auth"].provider + sign_in_and_redirect @user, event: :authentication + end + end +end diff --git a/app/models/omniauth_user.rb b/app/models/omniauth_user.rb index 57841f6c..0d31ce46 100644 --- a/app/models/omniauth_user.rb +++ b/app/models/omniauth_user.rb @@ -2,4 +2,13 @@ class OmniauthUser < ActiveRecord::Base belongs_to :user validates :user, presence: true + + def self.from_omniauth(auth, current_user) + omniauth_user = find_by(provider: auth.provider, uid: auth.uid, email: auth.info.email) + return omniauth_user.user if omniauth_user.present? + + user = current_user || User.find_by(email: auth.info.email) || User.create(email: auth.info.email, password: Devise.friendly_token[0,20]) + user.omniauth_users.create(provider: auth.provider, uid: auth.uid, email: auth.info.email) + user + end end diff --git a/app/models/user.rb b/app/models/user.rb index 19c217b2..511c663f 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -3,10 +3,13 @@ require 'digest/md5' ## # a person using the Notebook.ai web application. Owns all other content. class User < ActiveRecord::Base + SOCIAL_SITES = [:facebook, :google_oauth2, :twitter] + # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable and :omniauthable devise :database_authenticatable, :registerable, - :recoverable, :rememberable, :trackable, :validatable + :recoverable, :rememberable, :trackable, :validatable, + :omniauthable, omniauth_providers: SOCIAL_SITES include HasContent include Authority::UserAbilities @@ -30,6 +33,8 @@ class User < ActiveRecord::Base has_many :content_change_events + has_many :omniauth_users + # TODO: Swap this out with a has_many when we transition from a scratchpad to users having multiple documents has_one :document diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index 8895a963..88f197dd 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -262,4 +262,8 @@ 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['FACEBOOK_KEY'], ENV['FACEBOOK_SECRET'] + config.omniauth :google_oauth2, ENV['GOOGLE_KEY'], ENV['GOOGLE_SECRET'] + config.omniauth :twitter, ENV['TWITTER_ID'], ENV['TWITTER_SECRET'] end diff --git a/config/routes.rb b/config/routes.rb index d2168728..bf2b8649 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -2,7 +2,7 @@ Rails.application.routes.draw do - devise_for :users, :controllers => { registrations: 'registrations' } + devise_for :users, controllers: { registrations: 'registrations', omniauth_callbacks: 'users/omniauth_callbacks' } resources :users get '/unsubscribe/emails/:code', to: 'emails#one_click_unsubscribe'