sign up with linkedIn account

This commit is contained in:
mlorb 2018-02-26 11:05:05 +01:00
parent 4d69636dbe
commit 08439e7f58
17 changed files with 206 additions and 7 deletions

View file

@ -17,6 +17,7 @@ gem 'font-awesome-rails', '~> 4.7.0.2'
gem 'recaptcha', require: 'recaptcha/rails'
gem 'sanitize', '~> 4.4'
gem 'omniauth'
gem 'omniauth-linkedin-oauth2'
# Gems for API implementation
gem 'jwt', '~> 1.5'

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View file

@ -1,6 +1,10 @@
module Users
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
include UsersGenerator
skip_before_action :verify_authenticity_token
before_action :sign_up_with_provider_enabled?,
only: :linkedin
# You should configure your model like this:
# devise :omniauthable, omniauth_providers: [:twitter]
@ -9,6 +13,55 @@ module Users
# def twitter
# end
def linkedin
auth_hash = request.env['omniauth.auth']
@user = User.from_omniauth(auth_hash)
if @user && @user.current_team_id?
# User already exists and has been signed up with LinkedIn; just sign in
set_flash_message(:notice,
:success,
kind: I18n.t('devise.linkedin.provider_name'))
sign_in_and_redirect @user
elsif @user
# User already exists and has started sign up with LinkedIn;
# but doesn't have team (needs to complete sign up - agrees to TOS)
set_flash_message(:alert,
:failure,
kind: I18n.t('devise.linkedin.provider_name'),
reason: I18n.t('devise.linkedin.complete_sign_up'))
redirect_to users_sign_up_provider_path(user: @user)
elsif User.find_by_email(auth_hash['info']['email'])
# email is already taken, so sign up with Linked in is not allowed
set_flash_message(:alert,
:failure,
kind: I18n.t('devise.linkedin.provider_name'),
reason: I18n.t('devise.linkedin.email_already_taken',
email: auth_hash['info']['email']))
redirect_to after_omniauth_failure_path_for(resource_name)
else
# Create new user and identity; and redirect to complete sign up form
@user = User.new(
full_name: auth_hash['info']['name'],
initials: generate_initials(auth_hash['info']['name']),
email: auth_hash['info']['email'],
password: generate_user_password
)
@user.avatar_remote_url = (auth_hash['info']['image'])
user_identity = UserIdentity.new(user: @user,
provider: auth_hash['provider'],
uid: auth_hash['uid'])
unless @user.save && user_identity.save
set_flash_message(:alert,
:failure,
kind: I18n.t('devise.linkedin.provider_name'),
reason: I18n.t('devise.linkedin.failed_to_save'))
redirect_to after_omniauth_failure_path_for(resource_name) and return
end
redirect_to users_sign_up_provider_path(user: @user)
end
end
# More info at:
# https://github.com/plataformatec/devise#omniauth
@ -28,5 +81,18 @@ module Users
# def after_omniauth_failure_path_for(scope)
# super(scope)
# end
private
def sign_up_with_provider_enabled?
render_403 unless Rails.configuration.x.enable_user_registration
render_403 unless Rails.configuration.x.linkedin_signin_enabled
end
def generate_initials(full_name)
initials = full_name.titleize.scan(/[A-Z]+/).join
initials = initials.strip.empty? ? 'PLCH' : initials[0..3]
initials
end
end
end

View file

@ -1,5 +1,9 @@
class Users::RegistrationsController < Devise::RegistrationsController
prepend_before_action :check_captcha, only: [:create]
before_action :registration_enabled?,
only: %i(new create new_with_provider create_with_provider)
before_action :sign_up_with_provider_enabled?,
only: %i(new_with_provider create_with_provider)
def avatar
user = User.find_by_id(params[:id]) || current_user
@ -122,12 +126,9 @@ class Users::RegistrationsController < Devise::RegistrationsController
end
end
def new
render_403 && return unless Rails.configuration.x.enable_user_registration
end
def new; end
def create
render_403 && return unless Rails.configuration.x.enable_user_registration
build_resource(sign_up_params)
valid_resource = resource.valid?
# ugly checking if new team on sign up is enabled :(
@ -174,6 +175,36 @@ class Users::RegistrationsController < Devise::RegistrationsController
end
end
def new_with_provider; end
def create_with_provider
@user = User.find_by_id(user_provider_params['user'])
# Create new team for the new user
@team = Team.new(team_provider_params)
@team.validate
if @team.valid? && Rails.configuration.x.new_team_on_signup
# Set the confirmed_at == created_at IF not using email confirmations
unless Rails.configuration.x.enable_email_confirmations
@user.update!(confirmed_at: @user.created_at)
end
@team.created_by = @user # set created_by for team
@team.save!
# Add this user to the team as owner
UserTeam.create(user: @user, team: @team, role: :admin)
# set current team to new user
@user.current_team_id = @team.id
@user.save!
sign_in_and_redirect @user
else
render :new_with_provider
end
end
protected
# Called upon creating User (before .save). Permits parameters and extracts
@ -191,6 +222,14 @@ class Users::RegistrationsController < Devise::RegistrationsController
tmp.merge(:initials => initials)
end
def team_provider_params
params.require(:team).permit(:name)
end
def user_provider_params
params.permit(:user)
end
def account_update_params
params.require(:user).permit(
:full_name,
@ -268,6 +307,14 @@ class Users::RegistrationsController < Devise::RegistrationsController
end
end
def registration_enabled?
render_403 unless Rails.configuration.x.enable_user_registration
end
def sign_up_with_provider_enabled?
render_403 unless Rails.configuration.x.linkedin_signin_enabled
end
# Redirect to login page after signing up
def after_sign_up_path_for(resource)
new_user_session_path

View file

@ -217,6 +217,14 @@ class User < ApplicationRecord
self.full_name = name
end
def avatar_remote_url=(url_value)
self.avatar = URI.parse(url_value)
# Assuming url_value is http://example.com/photos/face.png
# avatar_file_name == "face.png"
# avatar_content_type == "image/png"
@avatar_remote_url = url_value
end
def current_team
Team.find_by_id(self.current_team_id)
end

View file

@ -0,0 +1,37 @@
<% provide(:head_title, t('users.registrations.new.head_title')) %>
<div class="center-block center-block-narrow">
<h2><%= t 'users.registrations.new_with_provider.head_title' %></h2>
<div data-hook="sign-up-form-hook">
<%= form_for(:team, as: resource_name, url: users_complete_sign_up_provider_path, html: { id: "sign-up-provider-form" } ) do |f| %>
<%= hidden_field_tag :user, params['user'] %>
<% if Rails.configuration.x.new_team_on_signup %>
<div class="form-group" id="team_name_form">
<%= f.label :name, t('users.registrations.new.team_name_label') %>
<%= f.text_field :name, autofocus: true, class: 'form-control' %>
<span><small><%= t 'users.registrations.new.team_name_help' %></small></span>
</div>
<% end %>
<div class="form-group" data-hook="sign-up-form-submit">
<%= f.submit 'Sign up', class: 'btn btn-primary' %>
</div>
<% end %>
</div>
<%= render 'users/shared/links' %>
</div>
<% if @team and not @team.errors.empty? %>
<script>
(function () {
var formErrors = {};
<% @team.errors.each do |err, m| %>
formErrors["<%= err %>"] =["<%= m %>"];
<% end %>
$("form").renderFormErrors('team', formErrors, false);
}());
</script>
<% end %>

View file

@ -1,5 +1,7 @@
<%- if controller_name != 'sessions' %>
<%= link_to t("devise.links.login"), new_session_path(resource_name) %><br />
<% login = t("devise.links.login") %>
<% login = t("devise.links.login_with_provider") if ['new_with_provider', 'create_with_provider'].include? action_name %>
<%= link_to login, new_session_path(resource_name) %><br />
<% end -%>
<%- if devise_mapping.registerable? && Rails.configuration.x.enable_user_registration && controller_name != 'registrations' %>
@ -21,3 +23,14 @@
<%- if devise_mapping.omniauthable? && resource_class.omniauth_providers.any? %>
<div data-hook="omniauth-sign-in-links"></div>
<% end -%>
<%- if Rails.configuration.x.enable_user_registration && Rails.configuration.x.linkedin_signin_enabled %>
<%- if devise_mapping.omniauthable? && resource_class.omniauth_providers.any? && controller_name != 'registrations' %>
<%= link_to omniauth_authorize_path(resource_name, :linkedin), :title => "Sign in with LinkedIn" do %>
<%= image_tag 'linkedin/Sign-in-Small---Default.png', alt: "Sign in with LinkedIn",
onmouseover: "src='#{image_path('linkedin/Sign-in-Small---Hover.png')}'",
onmouseout: "src='#{image_path('linkedin/Sign-in-Small---Default.png')}'",
onclick: "src='#{image_path('linkedin/Sign-in-Small---Active.png')}'" %>
<% end -%>
<% end -%>
<% end -%>

View file

@ -102,6 +102,9 @@ Rails.application.configure do
config.x.enable_user_registration =
ENV['ENABLE_USER_REGISTRATION'] == 'false' ? false : true
# Enable sign in with LinkedIn account
config.x.linkedin_signin_enabled = ENV['LINKEDIN_SIGNIN_ENABLED'] == 'true'
# Use an evented file watcher to asynchronously detect changes in source code,
# routes, locales, etc. This feature depends on the listen gem.
#config.file_watcher = ActiveSupport::EventedFileUpdateChecker

View file

@ -116,6 +116,9 @@ Rails.application.configure do
config.x.enable_user_registration =
ENV['ENABLE_USER_REGISTRATION'] == 'false' ? false : true
# Enable sign in with LinkedIn account
config.x.linkedin_signin_enabled = ENV['LINKEDIN_SIGNIN_ENABLED'] == 'true'
# Use a different logger for distributed setups.
# require 'syslog/logger'
# config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name')

View file

@ -287,6 +287,8 @@ Devise.setup do |config|
# Add a new OmniAuth provider. Check the wiki for more information on setting
# up on your models and hooks.
# config.omniauth :github, 'APP_ID', 'APP_SECRET', scope: 'user,public_repo'
config.omniauth :linkedin, ENV['LINKEDIN_KEY'], ENV['LINKEDIN_SECRET'],
scope: %w(r_basicprofile r_emailaddress)
# ==> Warden configuration
# If you want to use other strategies, that are not supported by Devise, or

View file

@ -41,7 +41,8 @@ class Extends
# Data type name should match corresponding model's name
REPOSITORY_DATA_TYPES = { RepositoryTextValue: 0,
RepositoryDateValue: 1 }
RepositoryDateValue: 1,
RepositoryListValue: 2 }
# List of implemented core API versions
API_VERSIONS = ['20170715']
@ -49,7 +50,7 @@ class Extends
# Array used for injecting names of additional authentication methods for API
API_PLUGABLE_AUTH_METHODS = []
OMNIAUTH_PROVIDERS = []
OMNIAUTH_PROVIDERS = [:linkedin, *(:developer if Rails.env.development?)]
INITIAL_USER_OPTIONS = {}
end

View file

@ -11,6 +11,8 @@ Paperclip::Attachment.default_options.merge!(
url: '/system/:class/:attachment/:id_partition/:hash/:style/:filename'
)
Paperclip::UriAdapter.register
if ENV['PAPERCLIP_STORAGE'] == "s3"
if ENV['S3_BUCKET'].nil? or ENV['AWS_REGION'].nil? or

View file

@ -40,11 +40,17 @@ en:
submit: "Resend unlock instructions"
links:
login: "Log in"
login_with_provider: "Log in with SciNote account"
signup: "Sign up"
forgot: "Forgot your password?"
not_receive_confirmation: "Didn't receive confirmation instructions?"
not_receive_unlock: "Didn't receive unlock instructions?"
sign_in_provider: "Sign in with %{provider}"
linkedin:
provider_name: "LinkedIn"
complete_sign_up: "You have to complete the sign up process"
email_already_taken: "SciNote account with email %{email} alreday exists"
failed_to_save: "Failed to create new user"
helpers:
label:
@ -1272,6 +1278,8 @@ en:
head_title: "Sign up"
team_name_label: "Team name"
team_name_help: "Team name is required in order to create your own Team. After you create your own Team, you will be able to join other Teams as well."
new_with_provider:
head_title: "Complete the Sign up"
statistics:
title: "My statistics"
team: "Team"

View file

@ -498,6 +498,8 @@ Rails.application.routes.draw do
get 'avatar/:id/:style' => 'users/registrations#avatar', as: 'avatar'
post 'avatar_signature' => 'users/registrations#signature'
get 'users/auth_token_sign_in' => 'users/sessions#auth_token_create'
get 'users/sign_up_provider' => 'users/registrations#new_with_provider'
post 'users/complete_sign_up_provider' => 'users/registrations#create_with_provider'
end
namespace :api, defaults: { format: 'json' } do

View file

@ -69,6 +69,12 @@ namespace :data do
.where.not(invitation_token: nil)
.where("created_at < ?", Devise.invite_for.ago)
destroy_users(users)
# Remove users who didn't finish signup with LinkedIn
users = User.joins(:user_identities)
.where(confirmed_at: nil)
#.where('created_at < ?', Devise.confirm_within.ago)
destroy_users(users)
end
desc "Remove temporary and obsolete data"