diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index b879a4a8d..802dda3bc 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -13,6 +13,8 @@ class ApplicationController < ActionController::Base
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
+ before_action :ensure_signup_complete
+
rescue_from CanCan::AccessDenied do |exception|
redirect_to main_app.root_url, alert: exception.message
end
@@ -40,4 +42,13 @@ class ApplicationController < ActionController::Base
def set_debate_votes(debates)
@voted_values = current_user ? current_user.debate_votes(debates) : {}
end
+
+ def ensure_signup_complete
+ # Ensure we don't go into an infinite loop
+ return if action_name.in? %w(finish_signup do_finish_signup)
+
+ if user_signed_in? && !current_user.email_provided?
+ redirect_to finish_signup_path
+ end
+ end
end
diff --git a/app/controllers/users/omniauth_callbacks_controller.rb b/app/controllers/users/omniauth_callbacks_controller.rb
new file mode 100644
index 000000000..aac6583d1
--- /dev/null
+++ b/app/controllers/users/omniauth_callbacks_controller.rb
@@ -0,0 +1,30 @@
+class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
+ def self.provides_callback_for(provider)
+ class_eval %Q{
+ def #{provider}
+ @user = User.find_for_oauth(env["omniauth.auth"], current_user)
+
+ if @user.persisted?
+ sign_in_and_redirect @user, event: :authentication
+ set_flash_message(:notice, :success, kind: "#{provider}".capitalize) if is_navigational_format?
+ else
+ session["devise.#{provider}_data"] = env["omniauth.auth"]
+ redirect_to new_user_registration_url
+ end
+ end
+ }
+ end
+
+ # [:twitter, :facebook, :google_oauth2].each do |provider|
+ [:twitter].each do |provider|
+ provides_callback_for provider
+ end
+
+ def after_sign_in_path_for(resource)
+ if resource.email_provided?
+ super(resource)
+ else
+ finish_signup_path
+ end
+ end
+end
diff --git a/app/controllers/users/registrations_controller.rb b/app/controllers/users/registrations_controller.rb
index 0ef0ba638..d1fc54aab 100644
--- a/app/controllers/users/registrations_controller.rb
+++ b/app/controllers/users/registrations_controller.rb
@@ -1,4 +1,5 @@
class Users::RegistrationsController < Devise::RegistrationsController
+ prepend_before_filter :authenticate_scope!, only: [:edit, :update, :destroy, :finish_signup, :do_finish_signup]
def create
build_resource(sign_up_params)
@@ -9,6 +10,20 @@ class Users::RegistrationsController < Devise::RegistrationsController
end
end
+ def finish_signup
+ end
+
+ def do_finish_signup
+ if current_user.update(sign_up_params)
+ current_user.skip_reconfirmation!
+ sign_in(current_user, bypass: true)
+ redirect_to root_url, notice: I18n.t('devise.registrations.updated')
+ else
+ @show_errors = true
+ render :finish_signup
+ end
+ end
+
private
def sign_up_params
diff --git a/app/models/user.rb b/app/models/user.rb
index 544142c2f..4a1839b34 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -1,8 +1,12 @@
class User < ActiveRecord::Base
include ActsAsParanoidAliases
+
+ OMNIAUTH_EMAIL_PREFIX = 'omniauth@participacion'
+ OMNIAUTH_EMAIL_REGEX = /\A#{OMNIAUTH_EMAIL_PREFIX}/
+
apply_simple_captcha
devise :database_authenticatable, :registerable, :confirmable,
- :recoverable, :rememberable, :trackable, :validatable
+ :recoverable, :rememberable, :trackable, :validatable, :omniauthable
acts_as_voter
acts_as_paranoid column: :hidden_at
@@ -11,9 +15,11 @@ class User < ActiveRecord::Base
has_one :moderator
has_one :organization
has_many :inappropiate_flags
+ has_many :identities, dependent: :destroy
- validates :username, presence: true, unless: :organization?
+ validates :username, presence: true, unless: :organization?
validates :official_level, inclusion: {in: 0..5}
+ validates_format_of :email, without: OMNIAUTH_EMAIL_REGEX, on: :update
validates_associated :organization, message: false
@@ -25,6 +31,47 @@ class User < ActiveRecord::Base
scope :organizations, -> { joins(:organization) }
scope :officials, -> { where("official_level > 0") }
+ def self.find_for_oauth(auth, signed_in_resource = nil)
+ # Get the identity and user if they exist
+ identity = Identity.find_for_oauth(auth)
+
+ # If a signed_in_resource is provided it always overrides the existing user
+ # to prevent the identity being locked with accidentally created accounts.
+ # Note that this may leave zombie accounts (with no associated identity) which
+ # can be cleaned up at a later date.
+ user = signed_in_resource ? signed_in_resource : identity.user
+
+ # Create the user if needed
+ if user.nil?
+
+ # Get the existing user by email if the provider gives us a verified email.
+ # If no verified email was provided we assign a temporary email and ask the
+ # user to verify it on the next step via RegistrationsController.finish_signup
+ email_is_verified = auth.info.email && (auth.info.verified || auth.info.verified_email)
+ email = auth.info.email if email_is_verified
+ user = User.where(email: email).first if email
+
+ # Create the user if it's a new registration
+ if user.nil?
+ user = User.new(
+ username: auth.info.nickname || auth.extra.raw_info.name.parameterize('-') || auth.uid,
+ email: email ? email : "#{OMNIAUTH_EMAIL_PREFIX}-#{auth.uid}-#{auth.provider}.com",
+ password: Devise.friendly_token[0,20]
+ )
+ user.skip_confirmation!
+ user.save!
+ end
+ end
+
+ # Associate the identity with the user if needed
+ if identity.user != user
+ identity.user = user
+ identity.save!
+ end
+
+ user
+ end
+
def name
organization? ? organization.name : username
end
@@ -67,4 +114,8 @@ class User < ActiveRecord::Base
e.present? ? where(email: e) : none
end
+ def email_provided?
+ !!(email && email !~ OMNIAUTH_EMAIL_REGEX) ||
+ !!(unconfirmed_email && unconfirmed_email !~ OMNIAUTH_EMAIL_REGEX)
+ end
end
diff --git a/app/views/devise/_omniauth_form.html.erb b/app/views/devise/_omniauth_form.html.erb
new file mode 100644
index 000000000..888a3ba2f
--- /dev/null
+++ b/app/views/devise/_omniauth_form.html.erb
@@ -0,0 +1,5 @@
+
+
+<%= link_to t("omniauth.twitter.sign_in"), user_omniauth_authorize_path(:twitter), class: 'button radius expand' %>
+
+