authkit 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/FEATURES.md +73 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +168 -0
- data/Rakefile +60 -0
- data/authkit.gemspec +27 -0
- data/config/database.yml.example +19 -0
- data/lib/authkit.rb +5 -0
- data/lib/authkit/engine.rb +7 -0
- data/lib/authkit/version.rb +3 -0
- data/lib/generators/authkit/USAGE +18 -0
- data/lib/generators/authkit/install_generator.rb +113 -0
- data/lib/generators/authkit/templates/app/controllers/application_controller.rb +94 -0
- data/lib/generators/authkit/templates/app/controllers/email_confirmation_controller.rb +25 -0
- data/lib/generators/authkit/templates/app/controllers/password_change_controller.rb +29 -0
- data/lib/generators/authkit/templates/app/controllers/password_reset_controller.rb +29 -0
- data/lib/generators/authkit/templates/app/controllers/sessions_controller.rb +35 -0
- data/lib/generators/authkit/templates/app/controllers/users_controller.rb +89 -0
- data/lib/generators/authkit/templates/app/models/user.rb +170 -0
- data/lib/generators/authkit/templates/app/views/password_change/show.html.erb +16 -0
- data/lib/generators/authkit/templates/app/views/password_reset/show.html.erb +12 -0
- data/lib/generators/authkit/templates/app/views/sessions/new.html.erb +13 -0
- data/lib/generators/authkit/templates/app/views/users/edit.html.erb +58 -0
- data/lib/generators/authkit/templates/app/views/users/new.html.erb +58 -0
- data/lib/generators/authkit/templates/db/migrate/add_authkit_fields_to_users.rb +110 -0
- data/lib/generators/authkit/templates/db/migrate/create_users.rb +17 -0
- data/lib/generators/authkit/templates/lib/email_format_validator.rb +11 -0
- data/lib/generators/authkit/templates/spec/controllers/application_controller_spec.rb +188 -0
- data/lib/generators/authkit/templates/spec/controllers/email_confirmation_controller_spec.rb +80 -0
- data/lib/generators/authkit/templates/spec/controllers/password_change_controller_spec.rb +98 -0
- data/lib/generators/authkit/templates/spec/controllers/password_reset_controller_spec.rb +87 -0
- data/lib/generators/authkit/templates/spec/controllers/sessions_controller_spec.rb +111 -0
- data/lib/generators/authkit/templates/spec/controllers/users_controller_spec.rb +195 -0
- data/lib/generators/authkit/templates/spec/models/user_spec.rb +268 -0
- data/spec/spec_helper.rb +16 -0
- metadata +165 -0
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
require 'rails/generators/active_record'
|
3
|
+
|
4
|
+
module Authkit
|
5
|
+
class InstallGenerator < Rails::Generators::Base
|
6
|
+
include Rails::Generators::Migration
|
7
|
+
|
8
|
+
desc "An auth system for your Rails app"
|
9
|
+
|
10
|
+
def self.source_root
|
11
|
+
@source_root ||= File.join(File.dirname(__FILE__), 'templates')
|
12
|
+
end
|
13
|
+
|
14
|
+
def generate_authkit
|
15
|
+
generate_migration("create_users")
|
16
|
+
generate_migration("add_authkit_fields_to_users")
|
17
|
+
|
18
|
+
# Ensure the destination structure
|
19
|
+
empty_directory "app"
|
20
|
+
empty_directory "app/models"
|
21
|
+
empty_directory "app/controllers"
|
22
|
+
empty_directory "app/views"
|
23
|
+
empty_directory "app/views/users"
|
24
|
+
empty_directory "app/views/sessions"
|
25
|
+
empty_directory "app/views/password_reset"
|
26
|
+
empty_directory "app/views/password_change"
|
27
|
+
empty_directory "spec"
|
28
|
+
empty_directory "spec/models"
|
29
|
+
empty_directory "spec/controllers"
|
30
|
+
empty_directory "lib"
|
31
|
+
|
32
|
+
# Fill out some templates (for now, this is just straight copy)
|
33
|
+
template "app/models/user.rb", "app/models/user.rb"
|
34
|
+
template "app/controllers/users_controller.rb", "app/controllers/users_controller.rb"
|
35
|
+
template "app/controllers/sessions_controller.rb", "app/controllers/sessions_controller.rb"
|
36
|
+
template "app/controllers/password_reset_controller.rb", "app/controllers/password_reset_controller.rb"
|
37
|
+
template "app/controllers/password_change_controller.rb", "app/controllers/password_change_controller.rb"
|
38
|
+
template "app/controllers/email_confirmation_controller.rb", "app/controllers/email_confirmation_controller.rb"
|
39
|
+
|
40
|
+
template "spec/models/user_spec.rb", "spec/models/user_spec.rb"
|
41
|
+
template "spec/controllers/application_controller_spec.rb", "spec/controllers/application_controller_spec.rb"
|
42
|
+
template "spec/controllers/users_controller_spec.rb", "spec/controllers/users_controller_spec.rb"
|
43
|
+
template "spec/controllers/sessions_controller_spec.rb", "spec/controllers/sessions_controller_spec.rb"
|
44
|
+
template "spec/controllers/password_reset_controller_spec.rb", "spec/controllers/password_reset_controller_spec.rb"
|
45
|
+
template "spec/controllers/password_change_controller_spec.rb", "spec/controllers/password_change_controller_spec.rb"
|
46
|
+
template "spec/controllers/email_confirmation_controller_spec.rb", "spec/controllers/email_confirmation_controller_spec.rb"
|
47
|
+
|
48
|
+
template "lib/email_format_validator.rb", "lib/email_format_validator.rb"
|
49
|
+
|
50
|
+
# Don't treat these like templates
|
51
|
+
copy_file "app/views/users/new.html.erb", "app/views/users/new.html.erb"
|
52
|
+
copy_file "app/views/users/edit.html.erb", "app/views/users/edit.html.erb"
|
53
|
+
copy_file "app/views/sessions/new.html.erb", "app/views/sessions/new.html.erb"
|
54
|
+
copy_file "app/views/password_reset/show.html.erb", "app/views/password_reset/show.html.erb"
|
55
|
+
copy_file "app/views/password_change/show.html.erb", "app/views/password_change/show.html.erb"
|
56
|
+
|
57
|
+
# We don't want to override this file and may have a protected section
|
58
|
+
insert_at_end_of_class "app/controllers/application_controller.rb", "app/controllers/application_controller.rb"
|
59
|
+
|
60
|
+
# Need a temp root
|
61
|
+
route "root 'welcome#index'"
|
62
|
+
|
63
|
+
# Setup the routes
|
64
|
+
route "get '/email/confirm/:token', to: 'email_confirmation#show', as: :confirm"
|
65
|
+
|
66
|
+
route "post '/password/reset', to: 'password_reset#create'"
|
67
|
+
route "get '/password/reset', to: 'password_reset#show', as: :password_reset"
|
68
|
+
route "post '/password/change/:token', to: 'password_change#create'"
|
69
|
+
route "get '/password/change/:token', to: 'password_change#show', as: :password_change"
|
70
|
+
|
71
|
+
route "get '/signup', to: 'users#new', as: :signup"
|
72
|
+
route "get '/logout', to: 'sessions#destroy', as: :logout"
|
73
|
+
route "get '/login', to: 'sessions#new', as: :login"
|
74
|
+
|
75
|
+
route "put '/account', to: 'users#update'"
|
76
|
+
route "get '/account', to: 'users#edit', as: :user"
|
77
|
+
|
78
|
+
route "resources :sessions, only: [:new, :create, :destroy]"
|
79
|
+
route "resources :users, only: [:new, :create]"
|
80
|
+
|
81
|
+
# Support for has_secure_password and has_one_time_password
|
82
|
+
gem "active_model_otp"
|
83
|
+
gem "bcrypt-ruby", '~> 3.0.0'
|
84
|
+
|
85
|
+
# RSpec needs to be in the development group to be used in generators
|
86
|
+
gem_group :test, :development do
|
87
|
+
gem "rspec-rails"
|
88
|
+
gem "shoulda-matchers"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def self.next_migration_number(dirname)
|
93
|
+
ActiveRecord::Generators::Base.next_migration_number(dirname)
|
94
|
+
end
|
95
|
+
|
96
|
+
protected
|
97
|
+
|
98
|
+
def insert_at_end_of_class(filename, source)
|
99
|
+
source = File.expand_path(find_in_source_paths(source.to_s))
|
100
|
+
context = instance_eval('binding')
|
101
|
+
content = ERB.new(::File.binread(source), nil, '-', '@output_buffer').result(context)
|
102
|
+
insert_into_file "app/controllers/application_controller.rb", "#{content}\n", before: /end\n*\z/
|
103
|
+
end
|
104
|
+
|
105
|
+
def generate_migration(filename)
|
106
|
+
if self.class.migration_exists?("db/migrate", "#{filename}")
|
107
|
+
say_status "skipped", "Migration #{filename}.rb already exists"
|
108
|
+
else
|
109
|
+
migration_template "db/migrate/#{filename}.rb", "db/migrate/#{filename}.rb"
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
|
2
|
+
before_filter :set_time_zone
|
3
|
+
|
4
|
+
helper_method :logged_in?, :current_user
|
5
|
+
|
6
|
+
# It is very unlikely that this exception will be created under normal
|
7
|
+
# circumstances. Unique validations are handled in Rails, but they are
|
8
|
+
# also enforced at the database level to guarantee data integrity. In
|
9
|
+
# certain cases (double-clicking a save link, multiple distributed servers)
|
10
|
+
# it is possible to get past the Rails validation in which case the
|
11
|
+
# database throws an exception.
|
12
|
+
rescue_from ActiveRecord::RecordNotUnique, with: :record_not_unique
|
13
|
+
|
14
|
+
protected
|
15
|
+
|
16
|
+
def current_user
|
17
|
+
return @current_user if defined?(@current_user)
|
18
|
+
@current_user ||= User.find_by(session[:user_id]) if session[:user_id]
|
19
|
+
@current_user ||= User.user_from_remember_token(cookies.signed[:remember]) unless cookies.signed[:remember].blank?
|
20
|
+
session[:user_id] = @current_user.id if @current_user
|
21
|
+
session[:time_zone] = @current_user.time_zone if @current_user
|
22
|
+
set_time_zone
|
23
|
+
|
24
|
+
@current_user
|
25
|
+
end
|
26
|
+
|
27
|
+
def allow_tracking?
|
28
|
+
"#{request.headers['X-Do-Not-Track']}" != '1' && "#{request.headers['DNT']}" != '1'
|
29
|
+
end
|
30
|
+
|
31
|
+
def logged_in?
|
32
|
+
!!current_user
|
33
|
+
end
|
34
|
+
|
35
|
+
def require_login
|
36
|
+
deny_user(nil, login_path) unless logged_in?
|
37
|
+
end
|
38
|
+
|
39
|
+
def require_token
|
40
|
+
deny_user("Invalid token", root_path) unless @user = User.user_from_token(params[:token])
|
41
|
+
end
|
42
|
+
|
43
|
+
def login(user)
|
44
|
+
@current_user = user
|
45
|
+
current_user.track_sign_in(request.remote_ip) if allow_tracking?
|
46
|
+
current_user.set_token(:remember_token)
|
47
|
+
set_remember_cookie
|
48
|
+
reset_session
|
49
|
+
session[:user_id] = current_user.id
|
50
|
+
session[:time_zone] = current_user.time_zone
|
51
|
+
set_time_zone
|
52
|
+
current_user
|
53
|
+
end
|
54
|
+
|
55
|
+
def logout
|
56
|
+
current_user.clear_remember_token if current_user
|
57
|
+
cookies.delete(:remember)
|
58
|
+
reset_session
|
59
|
+
@current_user = nil
|
60
|
+
end
|
61
|
+
|
62
|
+
def set_time_zone
|
63
|
+
Time.zone = session[:time_zone] if session[:time_zone].present?
|
64
|
+
end
|
65
|
+
|
66
|
+
def set_remember_cookie
|
67
|
+
cookies.permanent.signed[:remember] = {
|
68
|
+
value: current_user.remember_token,
|
69
|
+
secure: Rails.env.production?
|
70
|
+
}
|
71
|
+
end
|
72
|
+
|
73
|
+
def redirect_back_or_default
|
74
|
+
redirect_to(session.delete(:return_url) || root_path)
|
75
|
+
end
|
76
|
+
|
77
|
+
def deny_user(message=nil, location=nil)
|
78
|
+
location ||= (logged_in? ? root_path : login_path)
|
79
|
+
|
80
|
+
session[:return_url] = request.fullpath
|
81
|
+
respond_to do |format|
|
82
|
+
format.json { render(status: 403, nothing: true) }
|
83
|
+
format.html do
|
84
|
+
flash[:error] = message || "Sorry, you must be logged in to do that"
|
85
|
+
redirect_to(location)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
false
|
90
|
+
end
|
91
|
+
|
92
|
+
def record_not_unique
|
93
|
+
respond_with(nil, location: root_path, status: 422)
|
94
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class EmailConfirmationController < ApplicationController
|
2
|
+
before_filter :require_token
|
3
|
+
|
4
|
+
respond_to :html
|
5
|
+
|
6
|
+
def show
|
7
|
+
if @user.email_confirmed
|
8
|
+
login(@user)
|
9
|
+
flash[:notice] = "Thanks for confirming your email address"
|
10
|
+
respond_to do |format|
|
11
|
+
format.json { head :no_content }
|
12
|
+
format.html { redirect_to root_path }
|
13
|
+
end
|
14
|
+
else
|
15
|
+
respond_to do |format|
|
16
|
+
format.json { render json: { status: 'error', errors: @user.errors }.to_json, status: 422 }
|
17
|
+
format.html {
|
18
|
+
flash[:error] = "Could not confirm email address because it is already in use"
|
19
|
+
redirect_to root_path
|
20
|
+
}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class PasswordChangeController < ApplicationController
|
2
|
+
before_filter :require_token
|
3
|
+
|
4
|
+
def show
|
5
|
+
respond_to do |format|
|
6
|
+
format.json { head :no_content }
|
7
|
+
format.html
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def create
|
12
|
+
if @user.change_password(params[:password], params[:password_confirmation])
|
13
|
+
login(@user)
|
14
|
+
|
15
|
+
respond_to do |format|
|
16
|
+
format.json { head :no_content }
|
17
|
+
format.html {
|
18
|
+
flash.now[:notice] = "Password updated successfully"
|
19
|
+
redirect_to(root_path)
|
20
|
+
}
|
21
|
+
end
|
22
|
+
else
|
23
|
+
respond_to do |format|
|
24
|
+
format.json { render json: { status: 'error', errors: @user.errors }.to_json, status: 422 }
|
25
|
+
format.html { render :show }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class PasswordResetController < ApplicationController
|
2
|
+
def show
|
3
|
+
end
|
4
|
+
|
5
|
+
def create
|
6
|
+
username_or_email = "#{params[:email]}".downcase
|
7
|
+
user = User.find_by_username_or_email(username_or_email) if username_or_email.present?
|
8
|
+
|
9
|
+
if user && user.send_reset_password
|
10
|
+
logout
|
11
|
+
|
12
|
+
respond_to do |format|
|
13
|
+
format.json { head :no_content }
|
14
|
+
format.html {
|
15
|
+
flash[:notice] = "We've sent an email which can be used to change your password"
|
16
|
+
redirect_to login_path
|
17
|
+
}
|
18
|
+
end
|
19
|
+
else
|
20
|
+
respond_to do |format|
|
21
|
+
format.json { render json: { errors: ["Invalid user name or email"], status: "error" }, status: 422 }
|
22
|
+
format.html {
|
23
|
+
flash.now[:error] = "Invalid user name or email"
|
24
|
+
render :show
|
25
|
+
}
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
class SessionsController < ApplicationController
|
2
|
+
# Login
|
3
|
+
def new
|
4
|
+
end
|
5
|
+
|
6
|
+
def create
|
7
|
+
username_or_email = "#{params[:email]}".downcase
|
8
|
+
user = User.find_by_username_or_email(username_or_email) if username_or_email.present?
|
9
|
+
|
10
|
+
if user && user.authenticate(params[:password])
|
11
|
+
login(user)
|
12
|
+
respond_to do |format|
|
13
|
+
format.json { head :no_content }
|
14
|
+
format.html { redirect_back_or_default }
|
15
|
+
end
|
16
|
+
else
|
17
|
+
respond_to do |format|
|
18
|
+
format.json { render json: { errors: ["Invalid user name or password"], status: "error" }, status: 422 }
|
19
|
+
format.html {
|
20
|
+
flash.now[:error] = "Invalid user name or password"
|
21
|
+
render :new
|
22
|
+
}
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Logout
|
28
|
+
def destroy
|
29
|
+
logout
|
30
|
+
respond_to do |format|
|
31
|
+
format.json { head :no_content }
|
32
|
+
format.html { redirect_to root_path }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
class UsersController < ApplicationController
|
2
|
+
before_filter :require_login, only: [:edit, :update]
|
3
|
+
|
4
|
+
respond_to :html, :json
|
5
|
+
|
6
|
+
# Signup
|
7
|
+
def new
|
8
|
+
@user = User.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def create
|
12
|
+
@user = User.new(user_create_params)
|
13
|
+
if @user.save
|
14
|
+
@user.send_confirmation
|
15
|
+
login(@user)
|
16
|
+
respond_to do |format|
|
17
|
+
format.json { head :no_content }
|
18
|
+
format.html { redirect_to root_path }
|
19
|
+
end
|
20
|
+
else
|
21
|
+
respond_to do |format|
|
22
|
+
format.json { render json: { status: 'error', errors: @user.errors }.to_json, status: 422 }
|
23
|
+
format.html { render :new }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def edit
|
29
|
+
@user = current_user
|
30
|
+
end
|
31
|
+
|
32
|
+
def update
|
33
|
+
@user = current_user
|
34
|
+
|
35
|
+
orig_confirmation_email = @user.confirmation_email
|
36
|
+
|
37
|
+
if @user.update_attributes(user_update_params)
|
38
|
+
# Send a new email confirmation if the user updated their email address
|
39
|
+
if @user.confirmation_email.present? &&
|
40
|
+
@user.confirmation_email != @user.email &&
|
41
|
+
@user.confirmation_email != orig_confirmation_email
|
42
|
+
@user.send_confirmation
|
43
|
+
end
|
44
|
+
respond_to do |format|
|
45
|
+
format.json { head :no_content }
|
46
|
+
format.html { redirect_to @user }
|
47
|
+
end
|
48
|
+
else
|
49
|
+
respond_to do |format|
|
50
|
+
format.json { render json: { status: 'error', errors: @user.errors }.to_json, status: 422 }
|
51
|
+
format.html { render :edit }
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
protected
|
57
|
+
|
58
|
+
# It would be nice to find a strategy to merge these. The only difference is that
|
59
|
+
# when signing up you are setting the email, and when changing your settings you
|
60
|
+
# are setting the confirmation email.
|
61
|
+
|
62
|
+
def user_create_params
|
63
|
+
params.require(:user).permit(
|
64
|
+
:email,
|
65
|
+
:username,
|
66
|
+
:password,
|
67
|
+
:password_confirmation,
|
68
|
+
:first_name,
|
69
|
+
:last_name,
|
70
|
+
:bio,
|
71
|
+
:website,
|
72
|
+
:phone_number,
|
73
|
+
:time_zone)
|
74
|
+
end
|
75
|
+
|
76
|
+
def user_update_params
|
77
|
+
params.require(:user).permit(
|
78
|
+
:confirmation_email,
|
79
|
+
:username,
|
80
|
+
:password,
|
81
|
+
:password_confirmation,
|
82
|
+
:first_name,
|
83
|
+
:last_name,
|
84
|
+
:bio,
|
85
|
+
:website,
|
86
|
+
:phone_number,
|
87
|
+
:time_zone)
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,170 @@
|
|
1
|
+
require 'email_format_validator'
|
2
|
+
|
3
|
+
class User < ActiveRecord::Base
|
4
|
+
has_secure_password
|
5
|
+
has_one_time_password
|
6
|
+
|
7
|
+
# Uncomment if you are not using strong params (note, that email is only permitted on
|
8
|
+
# signup and confirmation_email is only permitted on update):
|
9
|
+
#
|
10
|
+
# attr_accessible :username,
|
11
|
+
# :email,
|
12
|
+
# :confirmation_email,
|
13
|
+
# :password,
|
14
|
+
# :password_confirmation,
|
15
|
+
# :time_zone,
|
16
|
+
# :first_name,
|
17
|
+
# :last_name,
|
18
|
+
# :bio,
|
19
|
+
# :website,
|
20
|
+
# :phone_number
|
21
|
+
|
22
|
+
before_validation :downcase_email
|
23
|
+
before_validation :set_confirmation_email
|
24
|
+
|
25
|
+
# Whenever the password is set, validate (not only on create)
|
26
|
+
validates :password, presence: true, confirmation: true, length: {minimum: 6}, if: :password_set?
|
27
|
+
validates :username, presence: true, uniqueness: {case_sensitive: false}
|
28
|
+
validates :email, email_format: true, presence: true, uniqueness: true
|
29
|
+
validates :confirmation_email, email_format: true, presence: true
|
30
|
+
|
31
|
+
# Confirm emails check for existing emails for uniqueness as a convenience
|
32
|
+
validate :confirmation_email_uniqueness, if: :confirmation_email_set?
|
33
|
+
|
34
|
+
def self.user_from_token(token)
|
35
|
+
verifier = ActiveSupport::MessageVerifier.new(Rails.application.config.secret_token)
|
36
|
+
id = verifier.verify(token)
|
37
|
+
User.find_by_id(id)
|
38
|
+
rescue ActiveSupport::MessageVerifier::InvalidSignature
|
39
|
+
nil
|
40
|
+
end
|
41
|
+
|
42
|
+
# The tokens created by this method have unique indexes but they are digests of the
|
43
|
+
# id which is unique. Because of this we shouldn't see a conflict. If we do, however
|
44
|
+
# we want the ActiveRecord::StatementInvalid or ActiveRecord::RecordNotUnique exeception
|
45
|
+
# to bubble up.
|
46
|
+
def set_token(field)
|
47
|
+
return unless self.persisted?
|
48
|
+
verifier = ActiveSupport::MessageVerifier.new(Rails.application.config.secret_token)
|
49
|
+
self.send("#{field}_created_at=", Time.now)
|
50
|
+
self.send("#{field}=", verifier.generate(self.id))
|
51
|
+
self.save
|
52
|
+
end
|
53
|
+
|
54
|
+
# These methods are a little redundant, but give you the opportunity to
|
55
|
+
# insert expiry for any of these token based authentication strategies.
|
56
|
+
# For example:
|
57
|
+
#
|
58
|
+
# def self.user_from_remember_token(token)
|
59
|
+
# user = user_from_token(token)
|
60
|
+
# user = nil if user && user.remember_token_created_at < 30.days.ago
|
61
|
+
# user
|
62
|
+
# end
|
63
|
+
#
|
64
|
+
def self.user_from_remember_token(token)
|
65
|
+
user_from_token(token)
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.user_from_reset_password_token(token)
|
69
|
+
user_from_token(token)
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.user_from_confirmation_token(token)
|
73
|
+
user_from_token(token)
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.user_from_unlock_token(token)
|
77
|
+
user_from_token(token)
|
78
|
+
end
|
79
|
+
|
80
|
+
def display_name
|
81
|
+
[first_name, last_name].compact.join(" ")
|
82
|
+
end
|
83
|
+
|
84
|
+
def track_sign_in(ip)
|
85
|
+
self.sign_in_count += 1
|
86
|
+
self.last_sign_in_at = self.current_sign_in_at
|
87
|
+
self.last_sign_in_ip = self.current_sign_in_ip
|
88
|
+
self.current_sign_in_at = Time.now
|
89
|
+
self.current_sign_in_ip = ip
|
90
|
+
self.save
|
91
|
+
end
|
92
|
+
|
93
|
+
def clear_remember_token
|
94
|
+
self.remember_token = nil
|
95
|
+
self.remember_token_created_at = nil
|
96
|
+
self.save
|
97
|
+
end
|
98
|
+
|
99
|
+
def send_reset_password
|
100
|
+
return false unless set_token(:reset_password_token)
|
101
|
+
|
102
|
+
# TODO: insert your mailer logic here
|
103
|
+
true
|
104
|
+
end
|
105
|
+
|
106
|
+
def send_confirmation
|
107
|
+
return false unless set_token(:confirmation_token)
|
108
|
+
|
109
|
+
# TODO: insert your mailer logic here
|
110
|
+
true
|
111
|
+
end
|
112
|
+
|
113
|
+
def email_confirmed
|
114
|
+
return false if self.confirmation_token.blank? || self.confirmation_email.blank?
|
115
|
+
|
116
|
+
self.email = self.confirmation_email
|
117
|
+
|
118
|
+
# Don't nil out the token unless the changes are valid as it may be
|
119
|
+
# needed again (when re-rendering the form, for instance)
|
120
|
+
if valid?
|
121
|
+
self.confirmation_token = nil
|
122
|
+
self.confirmation_token_created_at = nil
|
123
|
+
end
|
124
|
+
|
125
|
+
self.save
|
126
|
+
end
|
127
|
+
|
128
|
+
def change_password(password, password_confirmation)
|
129
|
+
self.password = password
|
130
|
+
self.password_confirmation = password_confirmation
|
131
|
+
|
132
|
+
# Don't nil out the token unless the changes are valid as it may be
|
133
|
+
# needed again (when re-rendering the form, for instance)
|
134
|
+
if valid?
|
135
|
+
self.reset_password_token = nil
|
136
|
+
self.reset_password_token_created_at = nil
|
137
|
+
end
|
138
|
+
|
139
|
+
self.save
|
140
|
+
end
|
141
|
+
|
142
|
+
protected
|
143
|
+
|
144
|
+
def password_set?
|
145
|
+
self.password.present?
|
146
|
+
end
|
147
|
+
|
148
|
+
def downcase_email
|
149
|
+
self.email = self.email.downcase if self.email
|
150
|
+
end
|
151
|
+
|
152
|
+
def set_confirmation_email
|
153
|
+
self.confirmation_email = self.email if self.confirmation_email.blank?
|
154
|
+
end
|
155
|
+
|
156
|
+
def confirmation_email_set?
|
157
|
+
confirmation_email.present? && confirmation_email_changed? && confirmation_email != email
|
158
|
+
end
|
159
|
+
|
160
|
+
# It is possible that a user will change their email, not confirm, and then
|
161
|
+
# sign up for the service again using the same email. If they later go to confirm
|
162
|
+
# the email change on the first account it will fail because the email will be
|
163
|
+
# used by the new signup. Though this is problematic it avoids the larger problem of
|
164
|
+
# users blocking new user signups by changing their email address to something they
|
165
|
+
# don't control. This check is just for convenience and does not need to
|
166
|
+
# guarantee uniqueness.
|
167
|
+
def confirmation_email_uniqueness
|
168
|
+
errors.add(:confirmation_email, :taken, value: email) if User.where('email = ?', confirmation_email).count > 0
|
169
|
+
end
|
170
|
+
end
|