Added trackable for sign_in_count, sign_in_at and sign_in_ip.
This commit is contained in:
parent
52885725a9
commit
f9c5dd6a79
|
@ -1,5 +1,6 @@
|
|||
module Devise
|
||||
ALL = [:authenticatable, :confirmable, :recoverable, :rememberable, :timeoutable, :validatable].freeze
|
||||
ALL = [:authenticatable, :confirmable, :recoverable, :rememberable,
|
||||
:trackable, :timeoutable, :validatable].freeze
|
||||
|
||||
# Maps controller names to devise modules
|
||||
CONTROLLERS = {
|
||||
|
|
|
@ -4,16 +4,13 @@
|
|||
# record is set, we set the last request time inside it's scoped session to
|
||||
# verify timeout in the following request.
|
||||
Warden::Manager.after_set_user do |record, warden, options|
|
||||
if record && record.respond_to?(:timeout?)
|
||||
scope = options[:scope]
|
||||
# Record may have already been logged out by another hook (ie confirmable).
|
||||
if warden.authenticated?(scope)
|
||||
last_request_at = warden.session(scope)['last_request_at']
|
||||
if record.timeout?(last_request_at)
|
||||
warden.logout(scope)
|
||||
throw :warden, :scope => scope, :message => :timeout
|
||||
end
|
||||
warden.session(scope)['last_request_at'] = Time.now.utc
|
||||
scope = options[:scope]
|
||||
if record && record.respond_to?(:timeout?) && warden.authenticated?(scope)
|
||||
last_request_at = warden.session(scope)['last_request_at']
|
||||
if record.timeout?(last_request_at)
|
||||
warden.logout(scope)
|
||||
throw :warden, :scope => scope, :message => :timeout
|
||||
end
|
||||
warden.session(scope)['last_request_at'] = Time.now.utc
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
# After each sign in, update sign in time, sign in count and sign in IP.
|
||||
Warden::Manager.after_authentication do |record, warden, options|
|
||||
scope = options[:scope]
|
||||
if Devise.mappings[scope].try(:trackable?) && warden.authenticated?(scope)
|
||||
old_current, new_current = record.current_sign_in_at, Time.now
|
||||
record.last_sign_in_at = old_current || new_current
|
||||
record.current_sign_in_at = new_current
|
||||
|
||||
old_current, new_current = record.current_sign_in_ip, warden.request.remote_ip
|
||||
record.last_sign_in_ip = old_current || new_current
|
||||
record.current_sign_in_ip = new_current
|
||||
|
||||
record.sign_in_count ||= 0
|
||||
record.sign_in_count += 1
|
||||
|
||||
record.save(false)
|
||||
end
|
||||
end
|
|
@ -75,6 +75,7 @@ module Devise
|
|||
options = modules.extract_options!
|
||||
modules = Devise.all if modules.include?(:all)
|
||||
modules -= Array(options.delete(:except))
|
||||
modules = Devise::ALL & modules
|
||||
|
||||
if !modules.include?(:authenticatable)
|
||||
modules = [:authenticatable] | modules
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
require 'devise/hooks/trackable'
|
||||
|
||||
module Devise
|
||||
module Models
|
||||
# Track information about your user sign in. It tracks the following columns:
|
||||
#
|
||||
# * sign_in_count - Increased every time a sign in is made (by form, openid, oauth)
|
||||
# * current_sign_in_at - A tiemstamp updated when the user signs in
|
||||
# * last_sign_in_at - Holds the timestamp of the previous sign in
|
||||
# * current_sign_in_ip - The remote ip updated when the user sign in
|
||||
# * last_sign_in_at - Holds the remote ip of the previous sign in
|
||||
#
|
||||
module Trackable
|
||||
end
|
||||
end
|
||||
end
|
|
@ -41,6 +41,16 @@ module Devise
|
|||
apply_schema :remember_created_at, DateTime
|
||||
end
|
||||
|
||||
# Creates sign_in_count, current_sign_in_at, last_sign_in_at,
|
||||
# current_sign_in_ip, last_sign_in_in.
|
||||
def trackable
|
||||
apply_schema :sign_in_count, Integer
|
||||
apply_schema :current_sign_in_at, DateTime
|
||||
apply_schema :last_sign_in_at, DateTime
|
||||
apply_schema :current_sign_in_ip, String
|
||||
apply_schema :last_sign_in_ip, String
|
||||
end
|
||||
|
||||
# Overwrite with specific modification to create your own schema.
|
||||
def apply_schema(name, type, options={})
|
||||
raise NotImplementedError
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
require 'test/test_helper'
|
||||
|
||||
class TrackableTest < ActionController::IntegrationTest
|
||||
|
||||
test "current and last sign in timestamps are updated on each sign in" do
|
||||
user = create_user
|
||||
assert_nil user.current_sign_in_at
|
||||
assert_nil user.last_sign_in_at
|
||||
|
||||
sign_in_as_user
|
||||
user.reload
|
||||
|
||||
assert_kind_of Time, user.current_sign_in_at
|
||||
assert_kind_of Time, user.last_sign_in_at
|
||||
|
||||
assert_equal user.current_sign_in_at, user.last_sign_in_at
|
||||
assert user.current_sign_in_at >= user.created_at
|
||||
|
||||
visit destroy_user_session_path
|
||||
new_time = 2.seconds.from_now
|
||||
Time.stubs(:now).returns(new_time)
|
||||
|
||||
sign_in_as_user
|
||||
user.reload
|
||||
assert user.current_sign_in_at > user.last_sign_in_at
|
||||
end
|
||||
|
||||
test "current and last sign in remote ip are updated on each sign in" do
|
||||
user = create_user
|
||||
assert_nil user.current_sign_in_ip
|
||||
assert_nil user.last_sign_in_ip
|
||||
|
||||
sign_in_as_user
|
||||
user.reload
|
||||
|
||||
assert_equal "127.0.0.1", user.current_sign_in_ip
|
||||
assert_equal "127.0.0.1", user.last_sign_in_ip
|
||||
end
|
||||
|
||||
test "increase sign in count" do
|
||||
user = create_user
|
||||
assert_nil user.sign_in_count
|
||||
|
||||
sign_in_as_user
|
||||
user.reload
|
||||
assert_equal 1, user.sign_in_count
|
||||
|
||||
visit destroy_user_session_path
|
||||
sign_in_as_user
|
||||
user.reload
|
||||
assert_equal 2, user.sign_in_count
|
||||
end
|
||||
|
||||
test "does not update anything if user is signed out along the way" do
|
||||
user = create_user(:confirm => false)
|
||||
sign_in_as_user
|
||||
|
||||
user.reload
|
||||
assert_nil user.current_sign_in_at
|
||||
assert_nil user.last_sign_in_at
|
||||
end
|
||||
end
|
|
@ -0,0 +1,5 @@
|
|||
require 'test/test_helper'
|
||||
|
||||
class TrackableTest < ActiveSupport::TestCase
|
||||
|
||||
end
|
|
@ -16,6 +16,10 @@ class Rememberable < User
|
|||
devise :authenticatable, :rememberable
|
||||
end
|
||||
|
||||
class Trackable < User
|
||||
devise :authenticatable, :trackable
|
||||
end
|
||||
|
||||
class Timeoutable < User
|
||||
devise :authenticatable, :timeoutable
|
||||
end
|
||||
|
@ -50,52 +54,47 @@ class ActiveRecordTest < ActiveSupport::TestCase
|
|||
modules.each do |mod|
|
||||
assert include_module?(klass, mod)
|
||||
end
|
||||
end
|
||||
|
||||
def assert_not_include_modules(klass, *modules)
|
||||
modules.each do |mod|
|
||||
(Devise::ALL - modules).each do |mod|
|
||||
assert_not include_module?(klass, mod)
|
||||
end
|
||||
end
|
||||
|
||||
test 'include by default authenticatable only' do
|
||||
assert_include_modules Authenticatable, :authenticatable
|
||||
assert_not_include_modules Authenticatable, :confirmable, :recoverable, :rememberable, :timeoutable, :validatable
|
||||
end
|
||||
|
||||
test 'add confirmable module only' do
|
||||
assert_include_modules Confirmable, :authenticatable, :confirmable
|
||||
assert_not_include_modules Confirmable, :recoverable, :rememberable, :timeoutable, :validatable
|
||||
end
|
||||
|
||||
test 'add recoverable module only' do
|
||||
assert_include_modules Recoverable, :authenticatable, :recoverable
|
||||
assert_not_include_modules Recoverable, :confirmable, :rememberable, :timeoutable, :validatable
|
||||
end
|
||||
|
||||
test 'add rememberable module only' do
|
||||
assert_include_modules Rememberable, :authenticatable, :rememberable
|
||||
assert_not_include_modules Rememberable, :confirmable, :recoverable, :timeoutable, :validatable
|
||||
end
|
||||
|
||||
test 'add trackable module only' do
|
||||
assert_include_modules Trackable, :authenticatable, :trackable
|
||||
end
|
||||
|
||||
test 'add timeoutable module only' do
|
||||
assert_include_modules Timeoutable, :authenticatable, :timeoutable
|
||||
assert_not_include_modules Timeoutable, :confirmable, :recoverable, :rememberable, :validatable
|
||||
end
|
||||
|
||||
test 'add validatable module only' do
|
||||
assert_include_modules Validatable, :authenticatable, :validatable
|
||||
assert_not_include_modules Validatable, :confirmable, :recoverable, :timeoutable, :rememberable
|
||||
end
|
||||
|
||||
test 'add all modules' do
|
||||
assert_include_modules Devisable,
|
||||
:authenticatable, :confirmable, :recoverable, :rememberable, :timeoutable, :validatable
|
||||
:authenticatable, :confirmable, :recoverable, :rememberable, :trackable, :timeoutable, :validatable
|
||||
end
|
||||
|
||||
test 'configure modules with except option' do
|
||||
assert_include_modules Exceptable, :authenticatable, :confirmable
|
||||
assert_not_include_modules Exceptable, :recoverable, :rememberable, :validatable
|
||||
assert_include_modules Exceptable, :authenticatable, :confirmable, :trackable, :timeoutable
|
||||
end
|
||||
|
||||
test 'set a default value for stretches' do
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
class Admin < ActiveRecord::Base
|
||||
devise :all, :except => [:recoverable, :confirmable, :rememberable, :validatable]
|
||||
devise :all, :except => [:recoverable, :confirmable, :rememberable, :validatable, :trackable]
|
||||
|
||||
def self.find_for_authentication(conditions)
|
||||
last(:conditions => conditions)
|
||||
|
|
|
@ -25,6 +25,7 @@ ActiveRecord::Schema.define(:version => 1) do
|
|||
t.confirmable
|
||||
t.recoverable
|
||||
t.rememberable
|
||||
t.trackable
|
||||
end
|
||||
|
||||
t.timestamps
|
||||
|
|
Loading…
Reference in New Issue